LINQ to Entities无法识别方法'System.Linq.IQueryable'

28
我想运行这个LINQ简单代码以获取LINQ记录数,但结果出现了以下错误。
var model = _db2.Persons.Select(
    (x, index) => new 
    {
        rn = index + 1,
        col1 = x.Id
    }).ToList();

错误:

LINQ to Entities不识别方法'System.Linq.IQueryable1[<>f__AnonymousType22 [System.Int32,System.Int32]] Select[Person,<>f__AnonymousType22](System.Linq.IQueryable1 [MvcApplication27.Models.Person], System.Linq.Expressions.Expression1[System.Func3 [MvcApplication27.Models.Person,System.Int32,<>f__AnonymousType2`2 [System.Int32,System.Int32]]])',且该方法无法转换为存储表达式。


看起来 Persons 不是 IQueryable,先尝试使用 CastOfType(如果它们存在的话)。 - King King
不,这是因为索引用于查找记录编号。 这是Code First,当我在lambda中删除索引时,我没有任何问题! - ehsan
作为标题的一部分,System.Linq.IQueryable是返回类型,而不是方法名。你在方括号中看到的内容([<>f__AnonymousType22 [System.Int32,System.Int32]])是如果你手动输入它,会出现在<int, f__AnonymousType22<>>中的内容。实际的函数在那个部分之后,即Select[Person,<>f_AnonymousType22](...) - Scott Chamberlain
2个回答

28

问题在于LINQ to Entities不知道如何将那个Select重载(给你索引的那个)转换为SQL查询。您可以通过先选择所需的部分(以避免不必要地选择每个列),然后执行AsEnumerable()将其作为IEnumerable<T>而不是IQueryable<T>,然后在C#中纯粹执行Select操作来解决这个问题(简而言之,IQueryable<T>会被转换为SQL,而IEnumerable<T>则在代码中运行)。

var model = _db2.Persons.Select(x => x.Id).AsEnumerable().Select(
    (id, index) => new
    {
        rn = index + 1,
        col1 = id
    }).ToList();

请注意,你所查询的结果似乎是无序的,因此每次调用时ID/索引对可能会发生变化。如果你期望结果一致,请按某个属性排序(例如_db2.Persons.OrderBy(...))。

编辑

添加Scott的评论:

这里是内置在框架中的所有Linq语句的列表及其兼容性参考


8
这是一个有用的参考链接,其中列出了.NET框架中所有内置的Linq语句及其兼容性列表,你可以点击这个链接查看:http://msdn.microsoft.com/en-us/library/bb738550.aspx。 - Scott Chamberlain
你不觉得2个select(select().AsEnumerable().Select())相比于一个简单的SQL语句会降低效率吗? - ehsan
@ehsan жҳҜзҡ„пјҢе®ғеҸҜд»ҘпјҢдҪҶжҳҜдҪ дёҚиғҪеңЁEntityжЎҶжһ¶дёӯдҪҝз”ЁSelect<T, int>(...)еҮҪж•°гҖӮдҪ йңҖиҰҒдҪҝз”ЁжҹҘиҜўиҜӯжі•дёҺletжҲ–иҖ…дҪҝз”ЁжҜ”дҪ зҺ°еңЁжңүзҡ„жӣҙеӨҚжқӮзҡ„ж–№жі•иҜӯжі•пјҲжҲ‘и®Өдёәиҝҷе°ҶеӨ§еӨ§йҷҚдҪҺеҸҜиҜ»жҖ§пјүгҖӮ - Scott Chamberlain
1
补充@ScottChamberlain所说的,这里最大的性能问题是与数据库的I/O。由于我们仅选择了“Id”,因此在这里的性能应该与最佳可能的LINQ to Entities解决方案几乎相同。 - Tim S.

2
您可以只选择Id,然后使用Linq到对象创建自己的匿名对象,例如:
var model = _db2.Persons.Select(x => x.Id)
                        .ToList() // return int[]
                        .Select((id, index) => new
                                {
                                    rn = index + 1,
                                    col1 = id
                                 }) // return anonymous[] (with rn and col1)
                         .AsEnumerable(); // get an IEnumerable (readonly collection)

很可能这是因为Entity Framework不支持使用linq进行内存查询,所以在这种情况下,您可以只选择您需要的内容(例如id),然后使用ToList()方法执行查询,将其具体化,然后您就拥有了一个内存列表,因此,您可以使用linq to objects并按照您想要的方式使用支持的方法。


1
你可以在中间使用 AsEnumerable()。这样你就少用了一个 List() - xanatos
3
如果你能解释一下为什么需要这样做,那就太好了。(我本来想发表自己的回答,说类似的话,但对于新手来说,我不知道该如何解释为什么会发生这种情况。) - Scott Chamberlain

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