Vra

Ek probeer om 'n LINQ navraag uit te voer op 'n DataTable voorwerp en bizarre ek vind dat die uitvoering van so 'n navrae oor DataTables is nie eenvoudig. Byvoorbeeld:

var results = from myRow in myDataTable
where results.Field("RowNo") == 1
select results;

Dit is nie toegelaat nie. Hoe kan ek so iets werk te kry?

Ek is verbaas dat LINQ navrae nie toegelaat op DataTables!

Was dit nuttig?

Oplossing

Jy kan nie bevraagteken teen die DataTable se Rye versameling, aangesien DataRowCollection nie IEnumerable<T> implementeer. Wat jy nodig het om die AsEnumerable() uitbreiding vir DataTable gebruik. Soos so:

var results = from myRow in myDataTable.AsEnumerable()
where myRow.Field<int>("RowNo") == 1
select myRow;

En as Keith sê, sal jy nodig het om 'n verwysing na System.Data.DataSetExtensions

AsEnumerable() opbrengste IEnumerable<DataRow>. As jy nodig het om IEnumerable<DataRow> te skakel na 'n DataTable, gebruik die CopyToDataTable() uitbreiding.

Hier is navraag met Lambda Expression,

var result = myDataTable
    .AsEnumerable()
    .Where(myRow => myRow.Field<int>("RowNo") == 1);

Ander wenke

var results = from DataRow myRow in myDataTable.Rows
    where (int)myRow["RowNo"] == 1
    select myRow

Dit is nie dat hulle doelbewus nie toegelaat op DataTables, dis net dat DataTables pre-date die IQueryable en generiese IEnumerable konstrukte waarop Linq navrae kan gedoen word.

Beide koppelvlakke vereis 'n soort tipe-veiligheid bekragtiging. DataTables is nie sterk getik. Dit is dieselfde rede waarom mense nie kan navraag teen 'n Array List, byvoorbeeld.

Vir Linq te werk wat jy nodig het om jou resultate te karteer teen soort-veilige voorwerpe en navraag teen daardie plaas.

As @ ch00k gesê:

using System.Data; //needed for the extension methods to work

...

var results = 
    from myRow in myDataTable.Rows 
    where myRow.Field<int>("RowNo") == 1 
    select myRow; //select the thing you want, not the collection

Jy moet ook 'n verwysing projek toe te voeg tot System.Data.DataSetExtensions

var query = from p in dt.AsEnumerable()
                    where p.Field<string>("code") == this.txtCat.Text
                    select new
                    {
                        name = p.Field<string>("name"),
                        age= p.Field<int>("age")                         
                    };

Ek besef dit is 'n paar keer geantwoord oor, maar net na 'n ander benadering bied, ek wil die .Cast<T>() metode gebruik, dit help my handhaaf gesonde verstand in die sien van die eksplisiete aard omskryf en diep dink ek .AsEnumerable() anyways noem dit :

var results = from myRow in myDataTable.Rows.Cast<DataRow>()
                  where myRow.Field<int>("RowNo") == 1 select myRow;

of

var results = myDataTable.Rows.Cast<DataRow>()
                  .FirstOrDefault(x => x.Field<int>("RowNo") == 1);
//Create DataTable 
DataTable dt= new DataTable();
dt.Columns.AddRange(New DataColumn[]
{
   new DataColumn("ID",typeOf(System.Int32)),
   new DataColumn("Name",typeOf(System.String))

});

//Fill with data

dt.Rows.Add(new Object[]{1,"Test1"});
dt.Rows.Add(new Object[]{2,"Test2"});

//Now  Query DataTable with linq
//To work with linq it should required our source implement IEnumerable interface.
//But DataTable not Implement IEnumerable interface
//So we call DataTable Extension method  i.e AsEnumerable() this will return EnumerableRowCollection<DataRow>


// Now Query DataTable to find Row whoes ID=1

DataRow drow = dt.AsEnumerable().Where(p=>p.Field<Int32>(0)==1).FirstOrDefault();
 // 

Probeer hierdie eenvoudige lyn van navraag:

var result=myDataTable.AsEnumerable().Where(myRow => myRow.Field<int>("RowNo") == 1);

Jy kan LINQ gebruik om voorwerpe op die versameling rye, soos so:

var results = from myRow in myDataTable.Rows where myRow.Field("RowNo") == 1 select myRow;

Probeer hierdie

var row = (from result in dt.AsEnumerable().OrderBy( result => Guid.NewGuid()) select result).Take(3) ; 

Dit is 'n eenvoudige manier wat werk vir my en maak gebruik van lambda uitdrukkings:

var results = myDataTable.Select("").FirstOrDefault(x => (int)x["RowNo"] == 1)

En as jy 'n spesifieke waarde wil:

if(results != null) 
    var foo = results["ColName"].ToString()

Heel waarskynlik, die klasse vir die datastel, DataTable en DataRow is reeds gedefinieer in die oplossing. As dit die geval is, sal jy nie die DataSetExtensions verwysing benodig.

Ex. Dataset klas naam-> CustomSet, DataRow klas naam-> CustomTableRow (met gedefinieer kolomme: RowNo, ...)

var result = from myRow in myDataTable.Rows.OfType<CustomSet.CustomTableRow>()
             where myRow.RowNo == 1
             select myRow;

Of (as ek verkies)

var result = myDataTable.Rows.OfType<CustomSet.CustomTableRow>().Where(myRow => myRow.RowNo);
var results = from myRow in myDataTable
where results.Field<Int32>("RowNo") == 1
select results;

In my aansoek het ek gevind dat die gebruik van LINQ te Datastelle met die AsEnumerable () verlenging vir DataTable soos voorgestel in die antwoord was baie stadig. As jy belangstel in die optimalisering vir spoed is, gebruik James Newtonking se Json.Net biblioteek ( http: / /james.newtonking.com/json/help/index.html )

// Serialize the DataTable to a json string
string serializedTable = JsonConvert.SerializeObject(myDataTable);    
Jarray dataRows = Jarray.Parse(serializedTable);

// Run the LINQ query
List<JToken> results = (from row in dataRows
                    where (int) row["ans_key"] == 42
                    select row).ToList();

// If you need the results to be in a DataTable
string jsonResults = JsonConvert.SerializeObject(results);
DataTable resultsTable = JsonConvert.DeserializeObject<DataTable>(jsonResults);

Voorbeeld van hoe om dit te bereik hieronder:

DataSet dataSet = new DataSet(); //Create a dataset
dataSet = _DataEntryDataLayer.ReadResults(); //Call to the dataLayer to return the data

//LINQ query on a DataTable
var dataList = dataSet.Tables["DataTable"]
              .AsEnumerable()
              .Select(i => new
              {
                 ID = i["ID"],
                 Name = i["Name"]
               }).ToList();

Vir VB.NET sal die kode soos volg lyk:

Dim results = From myRow In myDataTable  
Where myRow.Field(Of Int32)("RowNo") = 1 Select myRow
IEnumerable<string> result = from myRow in dataTableResult.AsEnumerable()
                             select myRow["server"].ToString() ;

Probeer hierdie ...

SqlCommand cmd = new SqlCommand( "Select * from Employee",con);
SqlDataReader dr = cmd.ExecuteReader( );
DataTable dt = new DataTable( "Employee" );
dt.Load( dr );
var Data = dt.AsEnumerable( );
var names = from emp in Data select emp.Field<String>( dt.Columns[1] );
foreach( var name in names )
{
    Console.WriteLine( name );
}

Jy kan dit kry werk elegante via linQ soos volg:

from prod in TenMostExpensiveProducts().Tables[0].AsEnumerable()
where prod.Field<decimal>("UnitPrice") > 62.500M
select prod

Of soos dinamiese linQ hierdie (AsDynamic genoem direk op dataset):

TenMostExpensiveProducts().AsDynamic().Where (x => x.UnitPrice > 62.500M)

Ek verkies die laaste benadering tydjie is die mees buigsame. Post scriptum .: Moenie vergeet om System.Data.DataSetExtensions.dll verwysing verbind

jy kan dit probeer, maar jy moet seker wees dat die tipe van waardes vir elke kolom

List<MyClass> result = myDataTable.AsEnumerable().Select(x=> new MyClass(){
     Property1 = (string)x.Field<string>("ColumnName1"),
     Property2 = (int)x.Field<int>("ColumnName2"),
     Property3 = (bool)x.Field<bool>("ColumnName3"),    
});
Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top