【问题标题】:Binding DefaultExpression to property in Linq-to-Entities query将 DefaultExpression 绑定到 Linq-to-Entities 查询中的属性
【发布时间】:2012-10-04 17:28:14
【问题描述】:

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

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

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

这会构建,但在运行时,当实体框架表达式访问者实现通过树运行时,它会看到这一点并抛出“不支持”异常(如下)。似乎意思是我用作合并运算符表达式右侧的 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...

【问题讨论】:

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


    【解决方案1】:

    如您所述,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),
        )
    );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多