我正在使用OData Nuget包开发一个Web API原型。我在使用LINQ to EF查询时遇到了一些问题。
Here are my data model.它已经被高度简化了。
我正在尝试使用此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);
}
当尝试联合这两个查询时,我得到了这个错误:
<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.<ExecuteAsync>b__2(TraceRecord tr, Object value)
at System.Web.Http.Tracing.ITraceWriterExtensions.<>c__DisplayClass1b`1.<>c__DisplayClass1f.<TraceBeginEndAsync>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.<>c__DisplayClass1b`1.<TraceBeginEndAsync>b__12(TResult result)
at System.Threading.Tasks.TaskHelpersExtensions.<>c__DisplayClass3b`2.<Then>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 -但是返回这两个查询的Union会导致上面的distinct错误。
对我可能做错了什么有什么想法吗?
发布于 2013-03-21 14:44:31
看起来像是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,
})
});
}
这个想法是将导航属性从联合中删除,然后再将它们添加回来。只有当订单具有指向ProductA或ProductB的反向指针时,这才能起作用。
发布于 2013-03-22 02:10:00
这似乎是设计出来的(或者是有限制的)。对于集合操作(UNION,INTERSECT,EXCEPT),我们只允许模型类型和“平面”瞬态类型(即没有集合属性的行类型(例如,为投影而创建))。这里的解决方法是通过强制执行查询来在客户机上执行联合,即,而不是这样做:
var query3 = query1.Union(query2);
执行以下操作:
var query3 = query1.ToList().Union(query2);
发布于 2013-03-22 00:12:56
刚试过这个查询...这似乎是使用导航属性的唯一方法。
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.ProductAOrders
.Where(x => x.ProductAId == p.Id)
.Select(o => new Order
{
Id = o.ProductAId,
Date = o.Orders.Date
})
.Union( _context.ProductBOrders
.Where(x => x.ProductBId == p.Id)
.Select(o => new Order
{
Id = o.ProductBId,
Date = o.Orders.Date
}))
});
它会导致以下错误:
<Error><Message>An error has occurred.</Message><ExceptionMessage>The type 'API.Models.Product' appears in two structurally incompatible initializations within a single LINQ to Entities query. A type can be initialized in two places in the same query, but only if the same properties are set in both places and those properties are set in the same order.</ExceptionMessage><ExceptionType>System.NotSupportedException</ExceptionType><StackTrace> at System.Data.Objects.ELinq.ExpressionConverter.ValidateInitializerMetadata(InitializerMetadata metadata)
at System.Data.Objects.ELinq.ExpressionConverter.MemberInitTranslator.TypedTranslate(ExpressionConverter parent, MemberInitExpression 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.TranslateLambda(LambdaExpression lambda, DbExpression input)
at System.Data.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input, DbExpressionBinding& binding)
at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, DbExpression& source, DbExpressionBinding& sourceBinding, DbExpression& lambda)
at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.SelectTranslator.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.<ExecuteAsync>b__2(TraceRecord tr, Object value)
at System.Web.Http.Tracing.ITraceWriterExtensions.<>c__DisplayClass1b`1.<>c__DisplayClass1f.<TraceBeginEndAsync>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.<>c__DisplayClass1b`1.<TraceBeginEndAsync>b__12(TResult result)
at System.Threading.Tasks.TaskHelpersExtensions.<>c__DisplayClass3b`2.<Then>b__3a(Task`1 t)
at System.Threading.Tasks.TaskHelpersExtensions.ThenImpl[TTask,TOuterResult](TTask task, Func`2 continuation, CancellationToken cancellationToken, Boolean runSynchronously)</StackTrace></Error>
我不明白为什么“API.Models.Product”出现在一个LINQ to Entities查询中的两个结构不兼容的初始化中。
如果我替换掉
Orders = _context.ProductAOrders
.Where(x => x.ProductAId == p.Id)
.Select(o => new Order
{
Id = o.ProductAId,
Date = o.Orders.Date
})
.Union( _context.ProductBOrders
.Where(x => x.ProductBId == p.Id)
.Select(o => new Order
{
Id = o.ProductBId,
Date = o.Orders.Date
}))
这样(为了简单起见),我得到了相同的错误
Orders = _context.Orders.Select(o => new Order
{
Id = o.Id,
Date = o.Date
})
最近LINQ to EF似乎不是我最好的朋友:)
https://stackoverflow.com/questions/15509901
复制相似问题