2010-11-07 44 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();  
}