2

IQueryable で使用できる Linq 式を発行することにより、エンティティを POCO に投影するのに役立つクラスがあります。ここに私が問題を抱えている表現があります:

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

このステートメントでdPropertyは、PropertyInfoはバインディングの宛先プロパティを表す 、dTypeTypeそのプロパティの 、parameterExpressionは type のパラメーターを表す別の Linq 式TEntitysPropertyPropertyInfoソース プロパティを表すオブジェクトです。

これはビルドされますが、実行時に Entity Framework 式のビジター実装がツリーを介して動作するときに、これを確認して「サポートされていない」例外をスローします (下記)。意味のように見えるのは、合体演算子式の右側として使用している DefaultExpression が EF でサポートされていないことです。これに対処するドキュメントやディスカッションをかなり検索してみましたが、何も見つかりませんでした (もちろん、「デフォルト」のような単語で非常に適切な検索を行うことは困難です)。とにかく、C# の「デフォルト」演算子が Linq-to-Entities でサポートされていないというのは本当ですか? それが本当なら、私がやろうとしていること、つまりNullableジェネリック引数の型が宛先プロパティと同じである からプロパティを割り当てるにはどうすればよいですか?

つまり、ラムダとして記述した場合、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...
4

1 に答える 1

4

お気づきのとおり、LINQ-to-EntitiesはこのExpression.Defaultメソッドをサポートしていません。

ただし、LINQ-to-EntitiesはこのExpression.Constantメソッドをサポートしています。

ジェネリック型パラメーターを使用している場合は、合体操作の2番目のパラメーターを定数に設定するだけです。結局のところ、default(T)の同じインスタンスが与えられた場合、定数を返しますT

これを行うためのコードは次のとおりです。

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

ジェネリックスを使用していないと想定しているため、ここでdefaultキーワードを使用することはできません。ただし、を指定して取得するメソッドを作成Typeできます。

(コード外のルールの体系化に基づくソリューションに依存したくない場合は、インスタンスのみでオンザフライの結果を取得できることに注意してくださいExpression.DefaultType。)

それができたら、次のことができます。

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 に答える