在LINQ to entities中使用返回IQueryable的自定义方法

3

我有两个返回IQueryable的方法:

IQueryable<Person> GetGoodPeople();

并且

IQueryable<Person> GetBadPeople(); 

我需要编写这个查询:

var q = from x in GetGoodPeople()
        from y in GetBadPeople()
        select new { Good = x, Bad = y };

除非我声明一个变量并在查询中使用它,否则上述代码不受linq to entities支持(会抛出NotSupportedException异常):

var bad = GetBadPeople()
var q = from x in GetGoodPeople()
        from y in bad
        select new { Good = x, Bad = y };

有没有一种方法可以直接在Linq to Entities中使用IQueryable方法?

2
你在执行时遇到了什么错误?同时请展示一下GetGoodPeople()的实现。 - LifeOfPi
异常是:System.NotSupportedExceptionLINQ to Entities 不识别 'System.Linq.IQueryable`1[...] Query...' 方法,该方法无法转换为存储表达式。 - Khodaie
属性很好用,但如果我需要一些参数,它们就无法帮助我。 - Khodaie
正如@barakcaf建议的那样,尝试使用Persons.Select(x => x.whatever).AsEnumerable().Select( (whatever, index) => new { rn = index + 1, col1 = whatever }).ToList(); - LifeOfPi
1
虽然这是可能的,但任何解决这个问题的方案无疑都比你目前使用本地的解决方案更费力。 - Servy
显示剩余4条评论
2个回答

4

简短回答 - 不可行。你的修复方法是解决问题的正确方式。

一旦实体框架(以及LINQ2Sql)开始解析表达式树,就为时已晚。对GetBadPeople()的调用实际上是惰性执行的,并且因此试图将其转换为SQL本身。

以下是可能的样子:

Table(Person).Take(1).SelectMany(x => value(UserQuery).GetBadPeople(), (x, y) => new <>f__AnonymousType0`2(Good = x, Bad = y))

这里,我将GetGoodPeople()简单地写成返回People.Take(1)。请注意,该查询是逐字的,但是GetBadPeople()包含一个函数调用。

你在表达式外部评估GetBadPeople()的解决方法是正确的。这会导致表达式树调用Expression.Constant(bad),而不是尝试调用GetBadPeople()

这使查询看起来像这样:

Table(Person).Take(1).SelectMany(x => value(UserQuery+<>c__DisplayClass1_0).bad, (x, y) => new <>f__AnonymousType0`2(Good = x, Bad = y))

请注意这里没有方法调用 - 我们只是传递变量。

2
可以,只是...没有那么容易。你需要将第一个表达式转换成第二个表达式。你可以编写一个方法来实现这一点。 - Servy
@Servy 你说得对,我的回答可能过于武断(因为它不是可行的)。我实际上有一个内联调用的解决方案在这里 - 尽管在使用流畅语法时需要更多的工作。 - Rob
抱歉,我是指查询语法。 - Rob
有趣的是,我以前从未考虑过这个问题,但为什么我们可以使用DbContext中的属性/方法,例如from a in db.TableA from b in db.TableB select new { a, b }是如何工作的? - Ivan Stoev
@IvanStoev 您可以使用属性,因为翻译器假设该属性仅是一个空的getter/setter。如果它看起来像实体上的属性,则直接将其转换为对列的引用。翻译器中有一些假设,使事情正常工作。另一方面,除非它们是少数几个白名单方法(例如min、count、group by等)中的一部分,否则永远不会翻译方法。 - Rob

0

您可以通过使用无限制的连接来近似笛卡尔积。它看起来不容易受到NotSupportedException的影响。我已经检查了后端,它生成一个单一的SQL语句。

var q = from x in GetGoodPeople()
        join y in GetBadPeople()
        on 1 equals 1
        select new { Good = x, Bad = y };

问题在于查询内部产生IQueryable的方法,因为查询提供程序不知道如何处理该方法。这并没有解决该问题。 - Servy
2
@Servy...除了Linq-to-entity正确解释连接的事实外,与OP声明变量的解决方法相同。这不是解决问题了吗? - Derpy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接