Requête LINQ sur un DataTable
j'essaie d'effectuer une requête LINQ sur un objet DataTable et bizarrement je trouve que l'exécution de telles requêtes sur des DataTables n'est pas simple. Par exemple:
var results = from myRow in myDataTable
where results.Field("RowNo") == 1
select results;
ceci n'est pas autorisé. Comment je fais pour qu'un truc comme ça marche?
je suis étonné que les requêtes LINQ ne soient pas autorisées sur les DataTables!
21 réponses
vous ne pouvez pas interroger contre le DataTable
's lignes collection, depuis DataRowCollection
ne met pas en œuvre IEnumerable<T>
. Vous devez utiliser l'extension AsEnumerable()
pour DataTable
. Comme ceci:
var results = from myRow in myDataTable.AsEnumerable()
where myRow.Field<int>("RowNo") == 1
select myRow;
et comme Keith le dit, vous devrez ajouter une référence au système .Données.Extensions des données
AsEnumerable()
renvoie IEnumerable<DataRow>
. Si vous avez besoin de convertir IEnumerable<DataRow>
en un DataTable
, utilisez l'extension CopyToDataTable()
.
var results = from DataRow myRow in myDataTable.Rows
where (int)myRow["RowNo"] == 1
select myRow
ce n'est pas qu'ils aient été délibérément interdits sur les DataTables, c'est juste que les DataTables datent d'avant les constructions IQueryable et générique IEnumerable sur lesquelles des requêtes Linq peuvent être effectuées.
les deux interfaces nécessitent une validation de type de sécurité. Les données ne sont pas fortement dactylographiées. C'est la même raison pour laquelle les gens ne peuvent pas interroger contre un ArrayList, par exemple.
pour que Linq fonctionne, vous devez cartographier vos résultats par type-safe les objets et les requêtes contre la place.
comme @ch00k a dit:
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
Vous devez également ajouter une référence de projet à 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")
};
var results = from myRow in tblCurrentStock.AsEnumerable()
where myRow.Field<string>("item_name").ToUpper().StartsWith(tbSearchItem.Text.ToUpper())
select myRow;
DataView view = results.AsDataView();
//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();
//
je me rends compte que cela a été répondu plusieurs fois, mais juste pour offrir une autre approche, j'aime utiliser la méthode .Cast<T>()
, il m'aide à maintenir la santé mentale en voyant le type explicite défini, et au fond je pense que .AsEnumerable()
appelle de toute façon:
var results = from myRow in myDataTable.Rows.Cast<DataRow>()
where myRow.Field<int>("RowNo") == 1 select myRow;
ou
var results = myDataTable.Rows.Cast<DataRow>()
.FirstOrDefault(x => x.Field<int>("RowNo") == 1);
vous pouvez utiliser LINQ pour les objets de la collection Rows, comme suit:
var results = from myRow in myDataTable.Rows where myRow.Field("RowNo") == 1 select myRow;
essayez cette ligne simple de requête:
var result=myDataTable.AsEnumerable().Where(myRow => myRow.Field<int>("RowNo") == 1);
Essayez cette
var row = (from result in dt.AsEnumerable().OrderBy( result => Guid.NewGuid()) select result).Take(3) ;
C'est une manière simple qui fonctionne pour moi et utilise des expressions lambda:
var results = myDataTable.Select("").FirstOrDefault(x => (int)x["RowNo"] == 1)
alors si vous voulez une valeur particulière:
if(results != null)
var foo = results["ColName"].ToString()
très probablement, les classes pour L'ensemble de données, DataTable et DataRow sont déjà définies dans la solution. Si c'est le cas, vous n'aurez pas besoin de la référence data set extensions.
ex. Nom de la classe de l'ensemble de données - > CustomSet, nom de la classe de DataRow - > CustomTableRow (avec les colonnes définies: RowNo,...)
var result = from myRow in myDataTable.Rows.OfType<CustomSet.CustomTableRow>()
where myRow.RowNo == 1
select myRow;
Ou (que je préfère)
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;
dans mon application, J'ai trouvé que L'utilisation de LINQ pour les ensembles de données avec l'extension AsEnumerable() pour datable comme suggéré dans la réponse était extrêmement lente. Si vous êtes intéressé par l'optimisation de la vitesse, utilisez celle de James Newtonking Json.Net bibliothèque ( ) 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);
IEnumerable<string> result = from myRow in dataTableResult.AsEnumerable()
select myRow["server"].ToString() ;
vous pouvez obtenir un travail élégant via linq comme ceci:
from prod in TenMostExpensiveProducts().Tables[0].AsEnumerable()
where prod.Field<decimal>("UnitPrice") > 62.500M
select prod
ou comme linq dynamique cela (Asdynamique est appelé directement sur L'ensemble de données):
TenMostExpensiveProducts().AsDynamic().Where (x => x.UnitPrice > 62.500M)
je préfère la dernière approche est la plus flexible.
P. S.: N'oubliez pas de connecter System.Data.DataSetExtensions.dll
référence
pour VB.NET le code ressemblera à ceci:
Dim results = From myRow In myDataTable
Where myRow.Field(Of Int32)("RowNo") = 1 Select myRow
exemple sur la façon d'y parvenir fourni ci-dessous:
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();
essayez ceci...
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 );
}
vous pouvez essayer cela, mais vous devez être sûr du type de valeurs pour chaque colonne
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"),
});