我有以下代码:
Expression<Func<Subscription, Service>> service2= subscription => (from relationship in subscription.ChildRelationships
select relationship.SecondService).FirstOrDefault();
它创建了一个表达式,我稍后可以将其用作实体框架的查询的一部分。我正在使用的实际代码有一个where子句,但为了便于阅读,我省略了它。这很好用,我可以在LINQPad中运行它,我正在用它进行测试。
如果我将代码更改为:
Expression<Func<Subscription, IQueryable<Service>>> service2= subscription => (from relationship in subscription.ChildRelationships
select relationship.SecondService);
它不再编译并出现以下错误:
无法将lambda表达式转换为 代表类型 'System.Func&LT; Farmworks.Data.Subscription,System.Linq.IQueryable&LT; Farmworks.Data.Service&GT;&GT;' 因为一些返回类型 块不是隐含的 可转换为代表返回 型
这似乎是因为作为导航属性的ChildRelationships没有实现IQueryable。它实际上是EntityCollection类型,它实现了IEnumerable,但不适合创建与EF一起使用的表达式。
我想我理解为什么第二块代码不起作用,并且想知道如何重写它以便它做到。令我困惑的是为什么第一块代码确实有效。它还使用ChildRelationships导航属性,但在成为与EF一起使用的表达式时没有任何问题。
任何人都可以放弃任何光明吗?
答案 0 :(得分:1)
问题不在于FirstOrDefault以某种方式使Expression工作;正如你所说的那样,ChildRelationships本身并没有实现IQueryable。您可以根据自己的需要以两种不同的方式解决这个问题。
您可以使用IEnumerable.AsQueryable方法。如果服务已经从上下文加载,这可能是最好的。
如果未加载服务,您可以根据需要使用Load或Include方法在适当的时候加载它们,然后使用上面的解决方案。
如果你有对ObjectContext的引用,你可以使用ObjectQuery,它实现了IQueryable:
Expression<Func<Subscription, MyEntities, IQueryable<Service>>> service2 =
(subscription, context) => (
from s in context.Subscriptions // here is the IQueryable
where s.Id == subscription.Id
from relationship in s.ChildRelationships
select relationship.SecondService);
答案 1 :(得分:0)
我认为CompiledQuery
课程在这种情况下可以帮到你:
Expression<Func<Subscription, IQueryable<Service>>> service2 =
CompiledQuery.Compile(
subscription => (
from relationship in subscription.ChildRelationships
select relationship.SecondService
)
);
答案 2 :(得分:0)
你需要它是IQueryable&lt; Service&gt;?我认为select正在返回IEnumerable&lt; Service&gt;。 LINQ直接在IEnumerables上运行,因此您可以将service2声明为Expression&lt; Func&lt; Subscription,IEnumerable&lt; Service&gt;&gt;&gt ;.