Truy vấn LINQ trên DataTable


1031

Tôi đang cố gắng thực hiện một truy vấn LINQ trên một đối tượng DataTable và thật kỳ lạ là tôi thấy rằng việc thực hiện các truy vấn như vậy trên DataTables không đơn giản. Ví dụ:

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

Điều này không được phép. Làm thế nào để tôi có được một cái gì đó như thế này làm việc?

Tôi ngạc nhiên khi các truy vấn LINQ không được phép trên DataTables!


3
Bạn có thể tìm thêm ví dụ LINQ / Lambda từ webmingle.blogspot.com/2010_09_01_archive.html

Câu trả lời:


1279

Bạn không thể truy vấn đối với các DataTable's Hàng sưu tập, vì DataRowCollectionkhông thực hiện IEnumerable<T>. Bạn cần sử dụng AsEnumerable()phần mở rộng cho DataTable. Thích như vậy:

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

Và như @Keith nói, bạn sẽ cần thêm một tham chiếu đến System.Data.DataSetExtensions

AsEnumerable()trả lại IEnumerable<DataRow>. Nếu bạn cần chuyển đổi IEnumerable<DataRow>sang a DataTable, hãy sử dụng CopyToDataTable()tiện ích mở rộng.

Dưới đây là truy vấn với Lambda Expression,

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

8
Phiên bản VB: Dim results = From myRow In myDataTable.AsEnumerable _ Where myRow.Field ("RowNo") = 1 _ Chọn myRow
Jeff

15
Tôi đã có một tài liệu tham khảo về dll được đề cập, nhưng đã bị mấtusing System.Data;
Luke Duddridge

5
Phiên bản VB cần chèn (Of String) giữa myRow.Field và ("RowNo"). Phần đó nên đọc: myRow.Field (Of String) ("RowNo") = 1 - Tham khảo @Cros bình luận.
yougotiger

8
giải pháp này là phức tạp không cần thiết. Sử dụng myDataTable.Rowsthay thế như @JoelFan đề xuất.
Âm mưu

10
@Markus Chỉ cần làm rõ, lý do mà giải pháp của @ JoelFan hoạt động myDataTable.Rowslà vì myRowbiến được truyền rõ ràng DataRow. Khi nó được biên dịch, truy vấn đó được viết lại myDataTable.Rows.Cast<DataRow>().Where(myRow => (int)myRow["RowNo"] == 1). Cá nhân, tôi không tìm thấy cuộc gọi AsEnumerable()nào phức tạp hơn cuộc gọi đến Cast<DataRow>(). Theo tôi biết, hiệu suất là như nhau, vì vậy đó chỉ là vấn đề ưu tiên.
Collin K

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

2
Còn về việc chọn nhiều hàng, thay vì chỉ hàng 1 thì sao?
Điều chỉnh

2
Chỉ cần xóa dòng "nơi" và bạn sẽ nhận được tất cả các hàng
JoelFan

1
Có, đây là cách tôi sử dụng để làm điều đó, ngoại trừ việc thay thế (int)myRow["RowNo"]bằng biểu mẫu chung myRow.Field<int>("RowNo")để hỗ trợ các loại nullable thuận tiện hơn.
Jonas

69

Không phải là họ cố tình không được phép trên DataTables, chỉ là DataTables có trước các cấu trúc IEnable và IEnumerable chung mà các truy vấn Linq có thể được thực hiện.

Cả hai giao diện yêu cầu một số loại xác nhận an toàn loại. DataTables không được gõ mạnh. Đây là cùng một lý do tại sao mọi người không thể truy vấn đối với một ArrayList, ví dụ.

Để Linq hoạt động, bạn cần ánh xạ kết quả của mình theo các đối tượng an toàn loại và truy vấn theo đó.


49

Như @ ch00k đã nói:

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

Bạn cũng cần thêm một tham chiếu dự án vào System.Data.DataSetExtensions


1
Nếu bạn cố gắng này, bạn sẽ tìm thấy nó sẽ không làm việc trừ khi bạn đặt một loại cụ thể về myRowhoặc sử dụng Cast<DataRow>()trên Rows. Tốt hơn để sử dụng AsEnumerable().
NetMage

1
@NetMage này hoạt động 12 năm trước khi tôi đăng nó. Miễn là bạn có System.LinqSystem.Data.DataSetExtensionssau đó myDataTable.Rowstrả về một bộ sưu tập vô số DataRow. Điều đó có thể đã thay đổi, đã một thập kỷ kể từ khi tôi sử dụng nó.
Keith

1
Thú vị - Tôi đoán rằng nó đã được thay đổi tại một số điểm, vì hiện tại nó không hoạt động trên .Net hoặc .Net Core.
NetMage

1
@NetMage có, tôi không ngạc nhiên khi các DataSettiện ích mở rộng không được đưa vào .NET Core hoặc .NET Standard, chúng đã lỗi thời khi tôi đăng câu trả lời này. Tôi thực sự sẽ không sử dụng DataSettrong các dự án mới, có các mô hình truy cập dữ liệu tốt hơn nhiều, cả về mã hóa và hiệu suất.
Keith

1
Họ ở đó, nhưng DataRowCollectionkhông thực hiện chính IEnumerable<T>xác IEnumerablevà vì vậy không hoạt động với LINQ được gõ mạnh.
NetMage

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

các trường tên và tuổi hiện là một phần của đối tượng truy vấn và có thể được truy cập như vậy: Console.WriteLine (query.name);


Làm thế nào tôi sử dụng tên? Ví dụ, MessageBox.Show(name)không xác định.

35

Tôi nhận ra điều này đã được trả lời một vài lần, nhưng chỉ để đưa ra một cách tiếp cận khác:

Tôi thích sử dụng .Cast<T>()phương pháp này, nó giúp tôi duy trì sự tỉnh táo khi nhìn thấy loại rõ ràng được xác định và sâu bên dưới tôi nghĩ .AsEnumerable()gọi nó là dù sao:

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

hoặc là

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

Như đã lưu ý trong các bình luận, không có hội đồng nào khác cần thiết vì đó là một phần của Linq ( Tham khảo )


5
Điều này hoạt động mà không cần tham khảo System.Data.DataSetExtensions.
dùng423430

29

Sử dụng LINQ để thao tác dữ liệu trong 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();

1
AsDataView không xuất hiện trong Intellisense đối với tôi. Tôi đã sử dụng System.Data.Linq và sử dụng System.Linq nhưng nó vẫn không hoạt động. Bạn có biết tôi đang thiếu gì không? Cảm ơn trước.
Naomi

@Naomi Nó đến từ 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

Hãy thử dòng truy vấn đơn giản này:

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

4
Tôi thích " Chuỗi phương thức " (như bạn đã làm ở đây) hơn " Cú pháp truy vấn " (trong câu trả lời được chấp nhận) đơn giản vì đây là mệnh đề cơ bản phù hợp trên một dòng và vẫn rất dễ đọc. Để mỗi người của họ.
MikeTeeVee

16

Bạn có thể sử dụng LINQ cho các đối tượng trên bộ sưu tập Hàng, như vậy:

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

1
DataTable.Rowskhông triển khai IEnumerable, tôi không thể thấy cách truy vấn này có thể biên dịch.
onedaywhen ngày

@encedaywhen Tôi chỉ thấy điều này được thực hiện trong một số mã và nó được biên dịch. Cố gắng tìm hiểu tại sao ngay bây giờ.
BVernon

... hoặc bạn chỉ có thể sử dụng biểu thức lọc trong phương thức Chọn: var results = myDataTable.Select ("RowNo = 1"); Điều này trả về một mảng DataRow.
Ishikawa

12

Đây là một cách đơn giản phù hợp với tôi và sử dụng các biểu thức lambda:

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

Sau đó, nếu bạn muốn một giá trị cụ thể:

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

11

Thử cái này

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

11

Nhiều khả năng, các lớp cho Dataset, DataTable và DataRow đã được xác định trong giải pháp. Nếu đó là trường hợp bạn sẽ không cần tham chiếu DataSetExtensions.

Ví dụ. Tên lớp Dataset-> Customset, Tên lớp DataRow-> CustomTableRow (với các cột được xác định: RowNo, ...)

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

Hoặc (như tôi thích)

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;

Câu trả lời này như rất nhiều vấn đề với nó.
Ông Anderson

8

Trong ứng dụng của mình, tôi thấy rằng việc sử dụng LINQ to Datasets với phần mở rộng AsEnumerable () cho DataTable như được đề xuất trong câu trả lời là cực kỳ chậm. Nếu bạn quan tâm đến việc tối ưu hóa tốc độ, hãy sử dụng thư viện Json.Net của James Newtonking ( 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);

Tôi nghi ngờ điều này là nhanh hơn, trong các trường hợp chung. Nó có tổng phí của hai tuần tự hóa, một giải tuần tự hóa và một hoạt động phân tích cú pháp. Bất kể, tôi đã từ chối vì nó không ngắn gọn, tức là việc tuần tự hóa / giải tuần tự hóa không làm rõ rằng mục đích là để lọc một danh sách.
một phu phu

@an phu, sử dụng phương thức mở rộng .AsEnumerable tạo ra một tập hợp các System.Data.DataRowđối tượng nặng . Bảng dữ liệu được tuần tự hóa và phân tích cú pháp tạo ra dữ liệu nhẹ chỉ bao gồm tên cột và giá trị của mỗi hàng. Khi truy vấn chạy, nó sẽ tải dữ liệu vào bộ nhớ, đối với một tập dữ liệu lớn có thể liên quan đến việc hoán đổi. Đôi khi, tổng chi phí của một số thao tác nhỏ hơn chi phí sao chép lượng lớn dữ liệu vào và ra khỏi bộ nhớ.
Hạ cánh vào

7

Đối với VB.NET Mã sẽ trông như thế này:

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

Ví dụ về cách đạt được điều này được cung cấp dưới đây:

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

Thử cái này...

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

Bạn có thể làm cho nó hoạt động thanh lịch thông qua linq như thế này:

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

Hoặc giống như linq động này (AsDocate được gọi trực tiếp trên Dataset):

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

Tôi thích cách tiếp cận cuối cùng trong khi là linh hoạt nhất. PS: Đừng quên kết nối System.Data.DataSetExtensions.dlltài liệu tham khảo


5

bạn có thể thử điều này, nhưng bạn phải chắc chắn loại giá trị cho mỗi Cột

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

Thế giới đã phát điên? Có gì sai với sql? DataRow [] drs = dt.Select ("id = 1"); Có lẽ điều này là quá dễ dàng.
Chương trình

0

Tôi đề xuất giải pháp sau đây:

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

Nhìn vào Tài liệu DataView , điều đầu tiên chúng ta có thể thấy là:

Đại diện cho chế độ xem dữ liệu, tùy chỉnh của DataTable để sắp xếp, lọc, tìm kiếm, chỉnh sửa và điều hướng.

Điều tôi nhận được từ điều này là DataTable có nghĩa là chỉ lưu trữ dữ liệu và DataView ở đó cho phép chúng tôi "truy vấn" đối với DataTable.

Đây là cách nó hoạt động trong trường hợp cụ thể này:

Bạn cố gắng thực hiện Câu lệnh SQL

SELECT *
FROM myDataTable
WHERE RowNo = 1

trong "ngôn ngữ DataTable". Trong C # chúng ta sẽ đọc nó như thế này:

FROM myDataTable
WHERE RowNo = 1
SELECT *

trong C # như thế này:

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});
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.