استعلام LINQ على DataTable
سؤال
أحاول إجراء استعلام LINQ على كائن DataTable ومن الغريب أنني أجد أن إجراء مثل هذه الاستعلامات على DataTables ليس بالأمر السهل.على سبيل المثال:
var results = from myRow in myDataTable
where results.Field("RowNo") == 1
select results;
هذا غير مسموح به.كيف يمكنني الحصول على شيء مثل هذا العمل؟
أنا مندهش من أن استعلامات LINQ غير مسموح بها على DataTables!
المحلول
لا يمكنك الاستعلام ضد DataTable
'س الصفوف جمع، منذ DataRowCollection
لا ينفذ IEnumerable<T>
.تحتاج إلى استخدام AsEnumerable()
تمديد ل DataTable
.مثل ذلك:
var results = from myRow in myDataTable.AsEnumerable()
where myRow.Field<int>("RowNo") == 1
select myRow;
وكما يقول كيث، ستحتاج إلى إضافة إشارة إلى System.Data.DataSetExtensions
AsEnumerable()
عائدات IEnumerable<DataRow>
.إذا كنت بحاجة إلى تحويل IEnumerable<DataRow>
إلى أ DataTable
, ، استخدم ال CopyToDataTable()
امتداد.
يوجد أدناه استعلام باستخدام تعبير Lambda،
var result = myDataTable
.AsEnumerable()
.Where(myRow => myRow.Field<int>("RowNo") == 1);
نصائح أخرى
var results = from DataRow myRow in myDataTable.Rows
where (int)myRow["RowNo"] == 1
select myRow
لا يعني ذلك أنه لم يتم السماح بها عمدًا في DataTables، بل إن الأمر يتعلق فقط بأن DataTables تسبق تاريخ IQueryable وبنيات IEnumerable العامة التي يمكن تنفيذ استعلامات Linq عليها.
تتطلب كلا الواجهتين بعض التحقق من سلامة النوع.لم يتم كتابة DataTables بقوة.وهذا هو نفس السبب الذي يجعل الأشخاص لا يستطيعون الاستعلام عن قائمة ArrayList، على سبيل المثال.
لكي يعمل Linq، يجب عليك تعيين نتائجك مقابل كائنات آمنة للنوع والاستعلام عنها بدلاً من ذلك.
كما قال @ch00k:
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
تحتاج أيضًا إلى إضافة مرجع المشروع إلى 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")
};
أدرك أنه قد تم الرد على هذا عدة مرات، ولكن فقط لتقديم نهج آخر، أود استخدام .Cast<T>()
الطريقة، فهي تساعدني في الحفاظ على سلامة العقل في رؤية النوع الصريح المحدد، وفي أعماقي على ما أعتقد .AsEnumerable()
يطلق عليه على أي حال:
var results = from myRow in myDataTable.Rows.Cast<DataRow>()
where myRow.Field<int>("RowNo") == 1 select myRow;
أو
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();
//
استخدام LINQ لمعالجة البيانات في DataSet/DataTable
var results = from myRow in tblCurrentStock.AsEnumerable()
where myRow.Field<string>("item_name").ToUpper().StartsWith(tbSearchItem.Text.ToUpper())
select myRow;
DataView view = results.AsDataView();
جرب سطر الاستعلام البسيط هذا:
var result=myDataTable.AsEnumerable().Where(myRow => myRow.Field<int>("RowNo") == 1);
يمكنك استخدام LINQ للكائنات الموجودة في مجموعة الصفوف، كما يلي:
var results = from myRow in myDataTable.Rows where myRow.Field("RowNo") == 1 select myRow;
جرب هذا
var row = (from result in dt.AsEnumerable().OrderBy( result => Guid.NewGuid()) select result).Take(3) ;
هذه طريقة بسيطة تناسبني وتستخدم تعبيرات لامدا:
var results = myDataTable.Select("").FirstOrDefault(x => (int)x["RowNo"] == 1)
ثم إذا كنت تريد قيمة معينة:
if(results != null)
var foo = results["ColName"].ToString()
على الأرجح، تم تعريف فئات DataSet وDataTable وDataRow بالفعل في الحل.إذا كان الأمر كذلك فلن تحتاج إلى مرجع DataSetExtensions.
السابق.اسم فئة DataSet-> CustomSet، اسم فئة DataRow-> CustomTableRow (مع الأعمدة المحددة:الصف لا،...)
var result = from myRow in myDataTable.Rows.OfType<CustomSet.CustomTableRow>()
where myRow.RowNo == 1
select myRow;
أو (كما أفضّل)
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;
وجدت في تطبيقي أن استخدام LINQ لمجموعات البيانات بامتداد AsEnumerable() لـ DataTable كما هو مقترح في الإجابة كان بطيئًا للغاية.إذا كنت مهتمًا بتحسين السرعة، فاستخدم مكتبة James Newtonking's Json.Net (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);
مثال على كيفية تحقيق ذلك موضح أدناه:
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();
بالنسبة لـ VB.NET سيكون الكود كالتالي:
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() ;
جرب هذا...
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 );
}
يمكنك جعله يعمل بشكل أنيق عبر linq مثل هذا:
from prod in TenMostExpensiveProducts().Tables[0].AsEnumerable()
where prod.Field<decimal>("UnitPrice") > 62.500M
select prod
أو مثل linq الديناميكي (يتم استدعاء AsDynamic مباشرة على DataSet):
TenMostExpensiveProducts().AsDynamic().Where (x => x.UnitPrice > 62.500M)
أفضّل النهج الأخير بينما هو الأكثر مرونة.ملاحظة.:لا تنسى الاتصال System.Data.DataSetExtensions.dll
مرجع
يمكنك تجربة ذلك، ولكن يجب أن تتأكد من نوع القيم لكل عمود
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"),
});