5

OData Nuget パッケージを使用して Web API プロトタイプに取り組んでいます。LINQ to EF クエリを動作させる際に問題が発生しています。

これが私のデータモデルです。非常に簡素化されています。

このDTOを使用してクエリを機能させようとしています:

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public IEnumerable<Order> Orders { get; set; }
}

public class Order
{
    public int Id { get; set; }
    public DateTime Date { get; set; }
}

クエリは次のようになります。

[Queryable]
public IQueryable<Product> Get()
{
    var productA = _context.ProductA
                            .Select(p => new Product
                                {
                                    Id = p.id,
                                    Name = p.name,
                                    Orders = p.ProductAOrders.Select(o => new Order
                                        {
                                            Id = o.OrderId,
                                            Date = o.Orders.Date,
                                        })
                                });

    var productB = _context.ProductB
                            .Select(p => new Product
                                {
                                    Id = p.Id,
                                    Name = p.Name,
                                    Orders = p.ProductBOrders.Select(o => new Order
                                        {
                                            Id = o.OrderId,
                                            Date = o.Orders.Date,
                                        })
                                });

    return productA.Union(productB);
}

2 つのクエリを結合しようとすると、次のエラーが発生します。

<Error><Message>An error has occurred.</Message><ExceptionMessage>The 'Distinct' operation cannot be applied to the collection ResultType of the specified argument.
Parameter name: argument</ExceptionMessage><ExceptionType>System.ArgumentException</ExceptionType><StackTrace>   at System.Data.Common.CommandTrees.ExpressionBuilder.Internal.ArgumentValidation.ValidateDistinct(DbExpression argument)
   at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.UnionTranslator.TranslateBinary(ExpressionConverter parent, DbExpression left, DbExpression right)
   at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.BinarySequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call)
   at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SequenceMethodTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, SequenceMethod sequenceMethod)
   at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent, MethodCallExpression linq)
   at System.Data.Objects.ELinq.ExpressionConverter.TypedTranslator`1.Translate(ExpressionConverter parent, Expression linq)
   at System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)
   at System.Data.Objects.ELinq.ExpressionConverter.Convert()
   at System.Data.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable`1 forMergeOption)
   at System.Data.Objects.ObjectQuery.ToTraceString()
   at System.Data.Entity.Internal.Linq.InternalQuery`1.ToString()
   at System.Data.Entity.Infrastructure.DbQuery`1.ToString()
   at System.Convert.ToString(Object value, IFormatProvider provider)
   at System.Web.Http.Tracing.Tracers.HttpActionDescriptorTracer.&lt;ExecuteAsync&gt;b__2(TraceRecord tr, Object value)
   at System.Web.Http.Tracing.ITraceWriterExtensions.&lt;&gt;c__DisplayClass1b`1.&lt;&gt;c__DisplayClass1f.&lt;TraceBeginEndAsync&gt;b__13(TraceRecord traceRecord)
   at System.Web.Http.Tracing.SystemDiagnosticsTraceWriter.Trace(HttpRequestMessage request, String category, TraceLevel level, Action`1 traceAction)
   at System.Web.Http.Tracing.ITraceWriterExtensions.&lt;&gt;c__DisplayClass1b`1.&lt;TraceBeginEndAsync&gt;b__12(TResult result)
   at System.Threading.Tasks.TaskHelpersExtensions.&lt;&gt;c__DisplayClass3b`2.&lt;Then&gt;b__3a(Task`1 t)
   at System.Threading.Tasks.TaskHelpersExtensions.ThenImpl[TTask,TOuterResult](TTask task, Func`2 continuation, CancellationToken cancellationToken, Boolean runSynchronously)
</StackTrace></Error>

productA または productB のいずれかを返すことができますが、これら 2 つのクエリの Union を返すと、上記の明確なエラーが発生します。

私が間違っているかもしれないことについてのアイデアはありますか?

4

3 に答える 3

5

EFのバグのように見えます。MEST (同じタイプの複数のエンティティ セット) を機能させようとしていると思います。あなたが持っていたクエリの代わりに、試すことができます、

public IQueryable<Product> Get()
{
    var productA = _context.ProductA
                            .Select(p => new Product
                            {
                                Id = p.id,
                                Name = p.name,
                            });

    var productB = _context.ProductB
                            .Select(p => new Product
                            {
                                Id = p.Id,
                                Name = p.Name,
                            });

    return
        productA
        .Union(productB)
        .Select(p => new Product
        {
            Id = p.Id,
            Name = p.Name,
            Orders = _context.Orders
                    .Where(o => o.ProductA.Id == p.Id || o.ProductB.Id == p.Id)
                    .Select(o => new Order
                    {
                        Id = o.OrderId,
                        Date = o.Orders.Date,
                    })
        });
}

アイデアは、ナビゲーション プロパティをユニオンから取り出し、後で追加し直すことです。これは、Orders が ProductA または ProductB へのバック ポインターを持っている場合にのみ機能します。

于 2013-03-21T06:44:31.390 に答える
1

これは仕様 (または制限) によるものと思われます。集合操作 (UNION、INTERSECT、EXCEPT) では、モデル タイプと「フラット」な一時的なタイプ (つまり、コレクション プロパティのない行タイプ (プロジェクション用に作成されたものなど)) のみが許可されます。ここでの回避策は、これを行う代わりに、クエリの実行を強制することにより、クライアントでユニオンを実行することです。

var query3 = query1.Union(query2);

これを行う:

var query3 = query1.ToList().Union(query2);
于 2013-03-21T18:10:00.073 に答える