2

我有一个类,它通过发出可与 IQueryable 一起使用的 Linq 表达式来帮助将实体投影到 POCO。这是一个我遇到麻烦的表达式:

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

在此语句中,dPropertyPropertyInfo表示绑定中目标属性的 a,dType是该Type属性的 ,parameterExpression是表示 type 参数的另一个 Linq 表达式TEntitysPropertyPropertyInfo表示源属性的对象。

这会构建,但在运行时,当实体框架表达式访问者实现通过树运行时,它会看到这一点并抛出“不支持”异常(如下)。似乎意思是我用作合并运算符表达式右侧的 DefaultExpression 在 EF 中不受支持。我尝试搜索很多解决此问题的文档或讨论,但找不到任何东西(当然,很难对“默认”之类的词进行很好的搜索)。无论如何,Linq-to-Entities 中是否不支持 C#“默认”运算符?如果是真的,那么我该如何做我想做的事情,即从其Nullable通用参数类型与目标属性相同的属性中分配一个属性?

换句话说,如果你将 linq 表达式写成 lambda,它看起来像这样:

(/*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...
4

1 回答 1

4

如您所述,LINQ-to-Entities 不支持该Expression.Default方法

但是,LINQ-to-Entities确实支持该Expression.Constant方法

如果您使用的是泛型类型参数,您可以简单地将合并操作的第二个参数设置为常量;毕竟,default(T)在给定相同实例的情况下,将返回一个常量T

执行此操作的代码如下:

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

我假设你没有使用泛型,所以你不能在这里使用default关键字。但是,您可以创建一个方法,在给定Type.

(注意,如果您不想依赖基于代码之外的规则编纂的解决方案,您可以只使用一个实例来获得Expression.Default即时Type结果。)

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

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),
    )
);
于 2012-10-04T18:03:31.463 回答