2010-11-07 24 views
17

所以我剛剛從亞馬遜LINQ to Objects Using C# 4.0: Using and Extending LINQ to Objects and Parallel LINQ (PLINQ)得到了一個建議。Linq使用.NET 4動態關鍵字的好例子?

它說,這本書介紹了使用dynamic關鍵字使用LINQ,這讓我想:

,你可以用dynamic關鍵字,你不能使用LINQ做,否則做什麼迷死人?

+1

如果我做一個動態對象LINQ查詢,我得到'錯誤CS1979:在源類型查詢表達式「動態」或類型「動態」的加入順序並不allowed':S。 – 2010-11-07 14:03:55

+0

稍微閱讀一下當前使用動態LINQ的限制以及解決它們的一些方法:http://weblogs.asp.net/davidfowler/archive/2010/08/04/dynamic-linq-a-little- more-dynamic.aspx – egoodberry 2010-11-07 14:42:11

回答

20

下面是一個想法:通過將LINQ與動態相結合,您可以查詢無類型數據集,就好像它們是鍵入的一樣。

例如,假設myDataSet是一個無類型的DataSet。有了動態打字和)稱爲AsDynamic(一個擴展方法,以下是可能的:

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

以下是如何定義AsDynamic擴展方法。注意它返回的動態IEnumerable的,這使得它適用於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); 
    } 
    } 
} 

通過繼承DynamicObject,這需要定製的優勢結合 - 在這裏你接手解決自己成員名稱的過程。在這種情況下,我們綁定get和set成員訪問來檢索或存儲底層DataRow中的對象。

+0

Awsome!當我看到這一點時,我有想法添加.ExecuteSql擴展方法,它允許直接使用LinqPad與SQL服務器連接。 [檢查出來...](http://stackoverflow.com/a/24885293/1016343) – Matt 2014-07-22 11:12:41

+0

儘管我已經習慣了它,現在感覺很自然,在我這個純粹主義者,這讓我相信'AsDynamic'應該被理想地命名爲「ToDynamic」。 「To」意味着身份更改轉換,而「As」本身意味着保留轉換的表示,就像關鍵字一樣。但無論如何,.NET有許多類似的'As's,比如'AsReadOnly'。 – nawfal 2015-08-01 09:24:03

2

喬的回答很酷。我有一個想法如何簡化使用。如果您添加到擴展類:

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

它允許使用這樣的查詢中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: 您需要添加下列引用:

  • System.Data.OleDbSystem.Data裝配到查詢性能
  • 添加System.Dynamic到查詢性能

更新: 我注意到,喬又增加了一個功能ExecuteQueryDynamiclatest Beta v4.53.03 of LinqPad,可用於實現這一目標,例如:

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

這將返回Customers表從Northwind數據庫爲IEnumerable<dynamic>,使用Linq2Sql連接。

0

我所做的事情讓我的結果是這樣,但我會認爲有更好的辦法。

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