2010-11-07 25 views
17

Vì vậy, tôi chỉ nhận được đề xuất từ ​​Amazon cho LINQ to Objects Using C# 4.0: Using and Extending LINQ to Objects and Parallel LINQ (PLINQ).Ví dụ hay về cách sử dụng từ khóa động 4 .NET với LINQ?

Nó nói rằng cuốn sách giới thiệu cách sử dụng các từ khóa dynamic với LINQ, mà đã cho tôi suy nghĩ:

Những loại khiếp sợ bạn có thể làm với các dynamic từ khóa mà bạn không thể làm được với LINQ khác?

+1

Nếu tôi thực hiện truy vấn LINQ trên đối tượng động, tôi nhận được 'lỗi CS1979: Biểu thức truy vấn trên loại nguồn 'động' hoặc với chuỗi tham gia thuộc loại 'động' không được phép': S. –

+0

Đọc một chút về những hạn chế hiện tại của việc sử dụng LINQ với các động lực và một số cách làm việc xung quanh chúng: http://weblogs.asp.net/davidfowler/archive/2010/08/04/dynamic-linq-a-little- more-dynamic.aspx – egoodberry

Trả lời

20

Đây là một ý tưởng: bằng cách kết hợp LINQ với động, bạn có thể truy vấn các tập dữ liệu chưa được phân loại như thể chúng được nhập. Ví dụ:

Ví dụ: giả sử rằng myDataSet là một Tập dữ liệu chưa được nhập. Với tính năng nhập động và phương thức mở rộng được gọi là AsDynamic(), bạn có thể làm như sau:

var query = from cust in myDataSet.Tables[0].AsDynamic() 
    where cust.LastName.StartsWith ("A") 
    orderby cust.LastName, cust.FirstName 
    select new { cust.ID, cust.LastName, cust.FirstName, cust.BirthDate }; 

Dưới đây là cách xác định phương pháp mở rộng AsDynamic. Chú ý cách nó trả IEnumerable năng động, mà làm cho nó phù hợp cho các truy vấn LINQ:

public static class Extensions 
{  
    public static IEnumerable<dynamic> AsDynamic (this DataTable dt) 
    { 
    foreach (DataRow row in dt.Rows) yield return row.AsDynamic(); 
    } 

    public static dynamic AsDynamic (this DataRow row) 
    { 
    return new DynamicDataRow (row); 
    } 

    class DynamicDataRow : DynamicObject 
    { 
    DataRow _row; 
    public DynamicDataRow (DataRow row) { _row = row; } 

    public override bool TryGetMember (GetMemberBinder binder, out object result) 
    { 
     result = _row[binder.Name]; 
     return true; 
    } 

    public override bool TrySetMember (SetMemberBinder binder, object value) 
    { 
     _row[binder.Name] = value; 
     return true; 
    } 

    public override IEnumerable<string> GetDynamicMemberNames() 
    { 
     return _row.Table.Columns.Cast<DataColumn>().Select (dc => dc.ColumnName); 
    } 
    } 
} 

By subclassing DynamicObject, điều này lợi dụng tùy chỉnh ràng buộc - nơi bạn đi qua quá trình giải quyết tên thành viên cho mình. Trong trường hợp này, chúng ta ràng buộc việc truy cập thành viên và thiết lập để truy xuất hoặc lưu trữ các đối tượng trong DataRow bên dưới.

+0

Awsome! Khi tôi thấy điều này, tôi đã có ý tưởng để thêm một phương thức mở rộng .ExecuteSql cho phép sử dụng LinqPad trực tiếp với các kết nối máy chủ SQL. [Kiểm tra nó ra ...] (http://stackoverflow.com/a/24885293/1016343) – Matt

+0

Mặc dù tôi đã quen với nó bây giờ và cảm thấy tự nhiên, có sự thuần khiết này trong tôi khiến tôi tin rằng 'AsDynamic' nên được đặt tên lý tưởng là 'ToDynamic'. 'To' ngụ ý một chuyển đổi nhận dạng thay đổi trong khi' As' tự nhiên ngụ ý một chuyển đổi bảo toàn đại diện, như 'là' từ khóa. Nhưng dù sao, .NET cũng giống như 'As', giống như 'AsReadOnly'. – nawfal

2

Câu trả lời của Joe thật tuyệt. Tôi có một ý tưởng làm thế nào để đơn giản hóa việc sử dụng. Nếu bạn thêm này đến lớp mở rộng:

public static class Extensions 
{  

    public static IEnumerable<dynamic> ExecuteSql(this UserQuery uq, string sql) 
    { 
     var connStr="Provider=SQLOLEDB.1;"+uq.Connection.ConnectionString; 

     OleDbConnection connection = new OleDbConnection(connStr); 
     DataSet myDataSet = new DataSet(); 
     connection.Open(); 

     OleDbDataAdapter DBAdapter = new OleDbDataAdapter(); 
     DBAdapter.SelectCommand = new OleDbCommand(sql, connection); 
     DBAdapter.Fill(myDataSet); 

     var result = myDataSet.Tables[0].AsDynamic(); 
     return result; 
    } 
} 

Nó cho phép sử dụng các truy vấn như thế này trong LINQPad:

void Main() 
{ 
    var query1 = from cust in this.ExecuteSql("SELECT * from Customers") 
     where cust.ContactName.StartsWith ("C") 
     orderby cust.ContactName 
     select new { cust.CustomerID, cust.ContactName, cust.City };   
    query1.Dump();  
} 

NB: Bạn cần phải thêm các tài liệu tham khảo sau đây:

  • Thêm System.Data.OleDb từ System.Data lắp ráp các thuộc tính truy vấn
  • Thêm System.Dynamic đến các thuộc tính truy vấn

Cập nhật: tôi nhận thấy rằng Joe đã bổ sung thêm một chức năng ExecuteQueryDynamic trong latest Beta v4.53.03 of LinqPad, có thể được sử dụng để đạt được điều này, ví dụ:

void Main() 
{ 
    var q=this.ExecuteQueryDynamic("select * from Customers"); 
    q.Dump(); 
} 

Điều này sẽ trả lại bảng Customers từ Cơ sở dữ liệu Northwind là IEnumerable<dynamic>, sử dụng kết nối Linq2Sql.

0

Điều tôi đã làm cho tôi kết quả là điều này, nhưng tôi nghĩ đó là một cách tốt hơn.

using (SqlConnection connection = new SqlConnection(this.Connection.ConnectionString)) 
{ 
    connection.Open(); 

    SqlCommand command = new SqlCommand(query, connection); 
    SqlDataReader reader = command.ExecuteReader(); 

    reader.Cast<IDataRecord>().AsQueryable().Dump();  
} 
Các vấn đề liên quan