DataTable'da LINQ sorgusu


1031

Bir DataTable nesnesi üzerinde bir LINQ sorgusu gerçekleştirmek çalışıyorum ve tuhaf bir şekilde ben DataTables üzerinde bu tür sorgulama yapmak kolay değil buluyorum. Örneğin:

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

Buna izin verilmiyor. Böyle bir şeyi nasıl çalıştırabilirim?

DataTable'larda LINQ sorgularına izin verilmediğine şaşırdım!


Yanıtlar:


1279

DataTable'S Rows koleksiyonuna karşı sorgulama yapamazsınız , çünkü DataRowCollectionuygulama yapmaz IEnumerable<T>. İçin AsEnumerable()uzantısını kullanmanız gerekir DataTable. Şöyle ki:

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

Ve @Keith diyor, sen bir başvuru eklemeniz gerekir System.Data.DataSetExtensions

AsEnumerable()döner IEnumerable<DataRow>. Eğer dönüştürmek gerekiyorsa IEnumerable<DataRow>bir etmek DataTable, kullanmak CopyToDataTable()uzantısı.

Aşağıda Lambda İfadesi,

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

8
VB Sürümü: Dim results = myRow Gönderen myDataTable.AsEnumerable _ Where myRow.Field ("RowNo") = 1 _ myRow'u seçin
Jeff

15
Zaten belirtilen dll referans vardı, ama eksikusing System.Data;
Luke Duddridge

5
VB sürümü myRow.Field ve ("RowNo") arasına (Of String) eklemek gerekir. Bu bölüm şöyle olmalıdır: myRow.Field (Of String) ("RowNo") = 1 - Reference @Cros yorumu.
Haziran'da

8
bu çözüm gereksiz yere karmaşıktır. Yerine myDataTable.Rows@JoelFan önerdiği gibi kullanın .
Komplo

10
@Markus Sadece açıklığa kavuşturmak için, @ JoelFan'ın çözümünün çalışmasının myDataTable.Rowsnedeni myRowdeğişkenin açık bir şekilde kullanılmasıdır DataRow. Derlendiğinde, bu sorgu yeniden yazılır myDataTable.Rows.Cast<DataRow>().Where(myRow => (int)myRow["RowNo"] == 1). Şahsen, çağrıdan AsEnumerable()daha karmaşık bir çağrı bulamıyorum Cast<DataRow>(). Bildiğim kadarıyla, performans aynı, bu yüzden sadece bir tercih meselesi.
Collin K

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

2
Sadece satır 1 yerine birden çok satır seçmeye ne dersiniz?
Adjit

2
Sadece "nerede" satırını çıkarın ve tüm satırları alacaksınız
JoelFan

1
Evet, nullable türlerini daha rahat bir şekilde desteklemek (int)myRow["RowNo"]için genel formla değiştirmek dışında bunu yapmak için bunu kullanıyorum myRow.Field<int>("RowNo").
Jonas

69

Bu, DataTable'larda kasten izin verilmedikleri için değil, sadece DataTables'ın, Linq sorgularının gerçekleştirilebileceği IQueryable ve genel IEnumerable yapılarının tarih öncesi tarihidir.

Her iki arabirim de bir tür güvenlik denetimi gerektirir. DataTable'lar güçlü biçimde yazılmamış. Örneğin, insanların bir ArrayList'e karşı sorgulama yapmamalarının nedeni de budur.

Linq'in çalışması için sonuçlarınızı tür güvenli nesnelerle eşlemeniz ve bunun yerine sorgulamanız gerekir.


49

@ Ch00k'nin dediği gibi:

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

Ayrıca bir proje referansı eklemeniz gerekir System.Data.DataSetExtensions


1
Eğer bu çalışırsanız üzerinde belirli tip koymak sürece, bunu iş olmaz bulacaksınız myRowveya kullanım Cast<DataRow>()üzerine Rows. Kullanmak daha iyi AsEnumerable().
NetMage

1
@NetMage, yayınladığımda 12 yıl önce çalıştı. Sürece sahip System.Linqve System.Data.DataSetExtensionssonra zaten myDataTable.Rowsnumaralandırılabilir bir koleksiyon döndürür DataRow. Bu değişmiş olabilir, kullandığımdan bu yana on yıl geçti.
Keith

1
İlginç - Sanırım .Net veya .Net Core üzerinde çalışmadığı için bir noktada değiştirildi.
NetMage

1
@NetMage evet, DataSetuzantıların .NET Core veya .NET Standard'a girmediğine şaşırmadım, bu cevabı gönderdiğimde zaten modası geçmişti. Gerçekten DataSetyeni projelerde kullanmam , hem kodlama hem de performans kolaylığı için çok daha iyi veri erişim modelleri var.
Keith

1
Onlar orada, ama sadece DataRowCollectionuygulamaz ve bu yüzden güçlü tip LINQ ile çalışmaz. IEnumerable<T>IEnumerable
NetMage

38
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")                         
                    };

ad ve yaş alanları artık sorgu nesnesinin bir parçasıdır ve şu şekilde erişilebilir: Console.WriteLine (query.name);


Adı nasıl kullanırım? Örneğin MessageBox.Show(name), tanımsız.

35

Bunun birkaç kez yanıtlandığını, ancak sadece başka bir yaklaşım sunmak için farkındayım:

.Cast<T>()Yöntemi kullanmayı seviyorum , tanımlanmış açık türü görmede akıl sağlığını korumama yardımcı oluyor ve derinlemesine düşünüyorum .AsEnumerable(), yine de çağırıyor:

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

veya

var results = myDataTable.Rows.Cast<DataRow>()
                      .FirstOrDefault(x => x.Field<int>("RowNo") == 1);

Yorumlarda belirtildiği gibi, Linq'in bir parçası olduğu için başka meclislere gerek yok ( Referans )


5
Bu, System.Data.DataSetExtensions başvurmadan çalışır.
user423430

29

DataSet / DataTable'daki verileri değiştirmek için LINQ kullanma

var results = from myRow in tblCurrentStock.AsEnumerable()
              where myRow.Field<string>("item_name").ToUpper().StartsWith(tbSearchItem.Text.ToUpper())
              select myRow;
DataView view = results.AsDataView();

1
AsDataView Intellisense'de benim için görünmüyor. System.Data.Linq kullanarak ve System.Linq kullanarak dahil ama yine de çalışmıyor. Neyi kaçırdığımı biliyor musun? Şimdiden teşekkürler.
Naomi

@Naomi Bu geliyor System.Data.DataSetExtensions.
Louis Waweru

29
//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();
 // 

22

Bu basit sorgu satırını deneyin:

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

4
" Yöntem Zinciri " ni (burada yaptığınız gibi) " Sorgu Sözdizimi " (kabul edilen cevapta) yerine tercih ediyorum, çünkü bu tek bir satıra uyan ve hala çok okunabilir olan temel bir nerede-madde. Her birine kendi.
MikeTeeVee

16

Satır koleksiyonundaki nesnelere LINQ kullanabilirsiniz, örneğin:

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

1
Çünkü DataTable.Rowsuygulanmaz IEnumerable, bu sorgunun nasıl derlendiğini göremiyorum.
oneday

@onedayBu kod bazı yapıldığını gördüm ve derleme yapar. Nedenini anlamaya çalışıyorum.
BVernon

... ya da sadece Select yönteminde bir filtre ifadesi kullanabilirsiniz: var results = myDataTable.Select ("RowNo = 1"); Bu bir DataRow dizisi döndürür.
Ishikawa

12

Bu benim için çalışan ve lambda ifadeleri kullanan basit bir yoldur:

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

Sonra belirli bir değer istiyorsanız:

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

11

Bunu dene

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

11

Büyük olasılıkla, DataSet, DataTable ve DataRow sınıfları zaten çözümde tanımlanmıştır. Bu durumda, DataSetExtensions referansına ihtiyacınız olmayacaktır.

Ör. DataSet sınıf adı-> CustomSet, DataRow sınıf adı-> CustomTableRow (tanımlı sütunlarla: RowNo, ...)

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

Veya (tercih ettiğim gibi)

var result = myDataTable.Rows.OfType<CustomSet.CustomTableRow>().Where(myRow => myRow.RowNo);

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

Bu cevap onunla ilgili birçok sorun olarak.
Bay Anderson

8

Uygulamamda, LINQ, DataTable için AsEnumerable () uzantısına sahip veri kümelerine yanıtın önerildiği gibi kullanılmasının son derece yavaş olduğunu gördüm. Hız optimizasyonu yapmakla ilgileniyorsanız, James Newtonking'in Json.Net kütüphanesini kullanın ( 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);

Bunun genel durumlarda daha hızlı olduğundan şüpheliyim. Bir adet serileştirme ve bir ayrıştırma işlemi olmak üzere iki serileştirme yükü vardır. Ne olursa olsun, özlü olmadığı için indirgedim, yani serileştirme / serileştirme, bir listeyi filtrelemek niyetinin açık olmadığını gösteriyor.
bir phu

@an phu, .AsEnumerable uzantısı yöntemini kullanarak ağır System.Data.DataRownesnelerin bir koleksiyon oluşturur . Serileştirilmiş ve ayrıştırılmış veri tablosu, yalnızca her satırın sütun adlarından ve değerlerinden oluşan hafif veriler oluşturur. Sorgu çalıştığında, verileri büyük bir veri kümesi için değiştirmeyi içerebilecek belleğe yükler. Bazen, birkaç işlemin yükü, büyük miktarda veriyi belleğe ve belleğe kopyalama yükünden daha azdır.
LandedGently

7

VB.NET için Kod şöyle görünecektir:

Dim results = From myRow In myDataTable  
Where myRow.Field(Of Int32)("RowNo") = 1 Select myRow

7
IEnumerable<string> result = from myRow in dataTableResult.AsEnumerable()
                             select myRow["server"].ToString() ;

7

Aşağıda sağlananlara nasıl ulaşılacağına dair örnek:

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();

6

Bunu dene...

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 );
}

5

Bunun gibi linq üzerinden zarif çalışmasını sağlayabilirsiniz:

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

Veya dinamik linq gibi bu (AsDynamic doğrudan DataSet üzerinde denir):

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

Son yaklaşımı tercih ederken en esnek olanıdır. Not: System.Data.DataSetExtensions.dllReferans bağlamayı unutmayın


5

bunu deneyebilirsiniz, ancak her Sütun için değer türünden emin olmalısınız

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"),    
});

Dünya çıldırdı mı? Sql ile sorun nedir? DataRow [] drs = dt.Select ("id = 1"); Belki bu çok kolay.
Programnik

0

Aşağıdaki çözümü öneriyorum:

DataView view = new DataView(myDataTable); 
view.RowFilter = "RowNo = 1";
DataTable results = view.ToTable(true);

DataView Belgelerine baktığımızda görebildiğimiz ilk şey şudur:

Sıralama, filtreleme, arama, düzenleme ve gezinme için DataTable'ın veritabanına göre özelleştirilebilir bir görünümünü temsil eder.

Ne alıyorum DataTable sadece veri depolamak içindir ve DataView orada bize DataTable karşı "sorgulamak" sağlar.

Bu, bu özel durumda şu şekilde çalışır:

SQL deyimini uygulamaya çalışın

SELECT *
FROM myDataTable
WHERE RowNo = 1

"DataTable dili". C # 'da şöyle okurduk:

FROM myDataTable
WHERE RowNo = 1
SELECT *

hangi C # gibi görünüyor:

DataView view = new DataView(myDataTable);  //FROM myDataTable
view.RowFilter = "RowNo = 1";  //WHERE RowNo = 1
DataTable results = view.ToTable(true);  //SELECT *

0
                    //Json Formating code
                    //DT is DataTable
                    var filter = (from r1 in DT.AsEnumerable()

                                  //Grouping by multiple columns 
                                  group r1 by new
                                  {
                                      EMPID = r1.Field<string>("EMPID"),
                                      EMPNAME = r1.Field<string>("EMPNAME"),

                                  } into g
                                  //Selecting as new type
                                  select new
                                  {

                                      EMPID = g.Key.EMPID,
                                      MiddleName = g.Key.EMPNAME});
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.