سؤال

أحاول إجراء استعلام 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"),    
});
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top