2013-03-20 133 views
2

我对表达式树有些新意,我只是不太明白一些东西。生成动态选择lambda表达式

我需要做的是发送一个值列表,并从这些值中选择一个实体的列。所以,我会打个电话是这样的:

DATASTORE<Contact> dst = new DATASTORE<Contact>();//DATASTORE is implemented below. 
List<string> lColumns = new List<string>() { "ID", "NAME" };//List of columns 
dst.SelectColumns(lColumns);//Selection Command 

我想,要翻译成这样的代码(Contact是使用EF4实体):

Contact.Select(i => new Contact { ID = i.ID, NAME = i.NAME }); 

所以我们可以说我有下面的代码:

public Class<t> DATASTORE where t : EntityObject 
{ 
    public Expression<Func<t, t>> SelectColumns(List<string> columns) 
    { 
     ParameterExpression i = Expression.Parameter(typeof(t), "i"); 
     List<MemberBinding> bindings = new List<MemberBinding>(); 

     foreach (PropertyInfo propinfo in typeof(t).GetProperties(BindingFlags.Public | BindingFlags.Instance)) 
     { 
      if (columns.Contains(propinfo.Name)) 
      { 
       MemberBinding binding = Expression.Bind(propinfo, Expression.Property(i, propinfo.Name)); 
       bindings.Add(binding); 
      } 
     } 

     Expression expMemberInit = Expression.MemberInit(Expression.New(typeof(t)), bindings); 
     return Expression.Lambda<Func<t, t>>(expMemberInit, i); 
    } 

当我运行上面的代码中,我得到了以下错误:

The entity or complex type 'Contact' cannot be constructed in a LINQ to Entities query.

我看着查询的机构,它发出下面的代码:

{i => new Contact() {ID = i.ID, NAME = i.NAME}} 

我敢肯定,我应该能够构建一个新的实体,因为我明确地写了这条线作为测试看看是否可以这样做:

.Select(i => new Contact{ ID = i.ID, NAME = i.NAME }) 

这工作,但我需要动态构建选择。

我试着反编译直接查询(第一次查看低级代码),但我无法完全翻译它。我输入的高级别代码:

Expression<Func<Contact, Contact>> expression = z => 
        new Contact { ID = z.ID, NAME = z.NAME }; 

改变在反编译器中使用我得到这个代码的框架:

ParameterExpression expression2; 
Expression<Func<Contact, Contact>> expression = 
    Expression.Lambda<Func<Contact, Contact>> 
     (Expression.MemberInit(Expression.New((ConstructorInfo) methodof(Contact..ctor), 
     new Expression[0]), new MemberBinding[] { Expression.Bind((MethodInfo) 
      methodof(Contact.set_ID), Expression.Property(expression2 = Expression.Parameter(typeof(Contact), "z"), (MethodInfo) 
      methodof(Contact.get_ID))), Expression.Bind((MethodInfo) 
      methodof(Contact.set_NAME), Expression.Property(expression2, (MethodInfo) 
       methodof(Contact.get_NAME))) }), new ParameterExpression[] { expression2 
     }); 

我已经看过几个地方,试图了解这一点,但我没有相当得到它呢。谁能帮忙?

这些都是我看过一些地方:

回答

1

当我最后一次做结果时,我将结果映射到未映射的类(不是实体),它的工作原理与其他代码中的一样。你确定没有像.Select(i => new Contact {ID = i.ID,NAME = i.NAME})这样的动态查询有效吗?

+0

你好Oleg,这是有道理的,但我不想为每个实体创建一个新的类,因为我的数据存储是巨大的。我还回去验证一个非动态查询确实只选择了我指定的列。 – cjohns 2013-03-26 14:50:03

+0

用EF 4试了一下,得到了NotSupportedException。也许它是一样的?如果整个实体被选中,它们可以在不同的地方被安全地缓存或重用,并且它们将总是具有实际的并发令牌。另一方面,如果某个实体太大,可以很容易地分解为主要和细节实体。 – Oleg 2013-03-27 09:35:06