【发布时间】:2014-04-30 23:17:04
【问题描述】:
我对表达式树有点陌生,只是有些东西不太了解。
我需要做的是发送一个值列表并从这些值中选择一个实体的列。所以我会这样打电话:
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);
}
当我运行上面的代码时,我得到了以下错误:
无法在 LINQ to Entities 查询中构造实体或复杂类型“联系人”。
我查看了查询的正文,它发出了以下代码:
{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
});
我已经查看了几个地方来尝试理解这一点,但我还没有完全明白。有人可以帮忙吗?
这些是我看过的一些地方:
- msdn blog -- 这正是我想要做的,但我的反编译代码没有 Expression.Call。
- msdn MemberInit
- msdn Expression Property
- stackoverflow EF only get specific columns -- 这很接近,但这似乎在做同样的事情,就好像我只是使用查询的选择一样。
- stackoverflow lambda expressions to be used in select query -- 这里的答案正是我想要做的,我只是不明白如何将反编译的代码翻译成 C#。
【问题讨论】:
标签: entity-framework lambda linq-to-entities expression-trees