将DefaultExpression绑定到Linq-to-Entities查询中的属性

时间:2012-10-04 17:28:15

标签: linq entity-framework linq-to-entities expression-trees

我有一个类通过发出可以与IQueryable一起使用的Linq表达式来帮助项目实体到POCO。这是一个表达式,我遇到了一些问题:

result = Expression.Bind(dProperty,
                         Expression.Coalesce(Expression.Property(parameterExpression, sProperty),
                                             Expression.Default(dType)));  

在此声明中,dProperty是表示绑定中目标属性的PropertyInfodType是该属性的TypeparameterExpression是另一个Linq表达式表示类型TEntity的参数,sProperty是表示源属性的PropertyInfo对象。

这构建,但是在运行时,当Entity Framework表达式访问器实现在树中运行时,它会看到这一点并抛出“不支持”异常(如下所示)。似乎意味着我在EF中不支持我使用的默认表达式作为合并运算符表达式的右侧。我试着搜索相当多的文档或讨论来解决这个问题并且找不到任何东西(当然,很难对'default'这样的单词进行非常好的搜索)。无论如何,Linq-to-Entities中不支持C#'默认'运算符吗?如果是,那么我该如何做我正在尝试做的事情,即从Nullable分配一个属性,其泛型参数类型与目标属性相同?

换句话说,如果你把它写成一个lambda:

,那么linq表达式会是这样的
(/*long*/dest, /*long?*/src) => dest = src ?? default(long)

这是例外。

System.NotSupportedException: Unknown LINQ expression of type 'Default'.
   at System.Linq.Expressions.EntityExpressionVisitor.Visit(Expression exp)
   at System.Data.Objects.ELinq.Funcletizer.<>c__DisplayClass5.<Nominate>b__4(Expression exp, Func`2 baseVisit)
   at System.Linq.Expressions.EntityExpressionVisitor.BasicExpressionVisitor.Visit(Expression exp)
   at System.Linq.Expressions.EntityExpressionVisitor.VisitBinary(BinaryExpression b)
   at System.Data.Objects.ELinq.Funcletizer.<>c__DisplayClass5.<Nominate>b__4(Expression exp, Func`2 baseVisit)
   at System.Linq.Expressions.EntityExpressionVisitor.BasicExpressionVisitor.Visit(Expression exp)
   at System.Linq.Expressions.EntityExpressionVisitor.VisitMemberAssignment(MemberAssignment assignment)
   at System.Linq.Expressions.EntityExpressionVisitor.VisitBinding(MemberBinding binding)
   at System.Linq.Expressions.EntityExpressionVisitor.VisitBindingList(ReadOnlyCollection`1 original)
   at System.Linq.Expressions.EntityExpressionVisitor.VisitMemberInit(MemberInitExpression init)
   at System.Data.Objects.ELinq.Funcletizer.<>c__DisplayClass5.<Nominate>b__4(Expression exp, Func`2 baseVisit)
   at System.Linq.Expressions.EntityExpressionVisitor.BasicExpressionVisitor.Visit(Expression exp)
   at System.Linq.Expressions.EntityExpressionVisitor.VisitExpressionList(ReadOnlyCollection`1 original)
   at System.Linq.Expressions.EntityExpressionVisitor.VisitInvocation(InvocationExpression iv)
   at System.Data.Objects.ELinq.Funcletizer.<>c__DisplayClass5.<Nominate>b__4(Expression exp, Func`2 baseVisit)
   at System.Linq.Expressions.EntityExpressionVisitor.BasicExpressionVisitor.Visit(Expression exp)
   at System.Linq.Expressions.EntityExpressionVisitor.VisitLambda(LambdaExpression lambda)
   at System.Data.Objects.ELinq.Funcletizer.<>c__DisplayClass5.<Nominate>b__4(Expression exp, Func`2 baseVisit)
   at System.Linq.Expressions.EntityExpressionVisitor.BasicExpressionVisitor.Visit(Expression exp)
   at System.Linq.Expressions.EntityExpressionVisitor.VisitUnary(UnaryExpression u)
   at System.Data.Objects.ELinq.Funcletizer.<>c__DisplayClass5.<Nominate>b__4(Expression exp, Func`2 baseVisit)
   at System.Linq.Expressions.EntityExpressionVisitor.BasicExpressionVisitor.Visit(Expression exp)
   at System.Linq.Expressions.EntityExpressionVisitor.VisitExpressionList(ReadOnlyCollection`1 original)
   at System.Linq.Expressions.EntityExpressionVisitor.VisitMethodCall(MethodCallExpression m)
   at System.Data.Objects.ELinq.Funcletizer.<>c__DisplayClass5.<Nominate>b__4(Expression exp, Func`2 baseVisit)
   at System.Linq.Expressions.EntityExpressionVisitor.BasicExpressionVisitor.Visit(Expression exp)
   at System.Data.Objects.ELinq.Funcletizer.Nominate(Expression expression, Func`2 localCriterion)
   at System.Data.Objects.ELinq.Funcletizer.Funcletize(Expression expression, Func`1& recompileRequired)
   at System.Data.Objects.ELinq.ExpressionConverter..ctor(Funcletizer funcletizer, Expression expression)
   at System.Data.Objects.ELinq.ELinqQueryState.CreateExpressionConverter()
   at System.Data.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption)
   at System.Data.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
   at System.Data.Objects.ObjectQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator()
   at System.Linq.Enumerable.<SelectManyIterator>d__14`2.MoveNext()
   at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
   at System.Linq.Enumerable.<TakeIterator>d__3a`1.MoveNext()
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Collections.Generic.List`1.InsertRange(Int32 index, IEnumerable`1 collection)
   at MyClass...

1 个答案:

答案 0 :(得分:4)

如您所知,LINQ-to-Entities不支持Expression.Default method

但是,LINQ-to-Entities 支持Expression.Constant method

如果使用泛型类型参数,则只需将合并操作的第二个参数设置为常量;毕竟,default(T)将返回一个给定相同T实例的常量。

执行此操作的代码如下:

result = Expression.Bind(dProperty, 
    Expression.Coalesce(
        Expression.Property(parameterExpression, sProperty),
        Expression.Constant(default(T), dType),
    )
);

我假设你不是使用泛型,所以你不能在这里使用default keyword。但是,您可以create a method that will get it for you given a Type

(注意,如果您不想依赖于基于代码之外的规则的编码的解决方案,you can get the result of Expression.Default on-the-fly with only a Type instance。)

完成后,您可以执行以下操作:

result = Expression.Bind(dProperty, 
    Expression.Coalesce(
        Expression.Property(parameterExpression, sProperty),
        // Note: The example referenced was changed to an extension method
        // on Type.
        Expression.Constant(dType.GetDefault(), dType),
    )
);