如何在LINQ中使用DbFunctions
本文关键字:DbFunctions LINQ | 更新日期: 2023-09-27 18:17:04
我有这个LINQ到实体:
var result = (from inspArch in inspectionArchives
from inspAuth in inspArch.InspectionAuthority
group new { inspArch, inspAuth } by inspArch.CustomerId into g
select new
{
clientId = g.Key,
id = g.Select(x => x.inspArch.Id).ToArray(),
authId = g.Select(x => x.inspAuth.Id).Distinct().ToArray()
});
但是在运行时我得到这个错误:
"LINQ to Entities does not recognize the method 'Int32[] ToArray[Int32](System.Collections.Generic.IEnumerable`1[System.Int32])' method, and this method cannot be translated into a store expression."
我知道我可以这样写我的LINQ:
var result = (from inspArch in inspectionArchives
from inspAuth in inspArch.InspectionAuthority
group new { inspArch, inspAuth } by inspArch.CustomerId into g
select new
{
clientId = g.Key,
id = g.Select(x => x.inspArch.Id),
authId = g.Select(x => x.inspAuth.Id).Distinct()
}).ToList();
然后:
var result2 = (from res in result
select new
{
clientId = res.clientId,
id = res.id.ToArray(),
authId = res.authId.ToArray()
});
它工作得很好,但是,它把整个表拉到内存中,然后应用投影,这不是很有效。
所以我读了关于DbFunctions类;是否有任何方法可以在这些行上使用提到的DbFunctions类?
id = g.Select(x => x.inspArch.Id).ToArray(),
authId = g.Select(x => x.inspAuth.Id).Distinct().ToArray()
代替ToArray()方法或另一种方法,使ToArray()方法可识别LINQ到实体?
你很接近了。这里没有任何与DbFunctions
相关的内容,您需要考虑的只是查询物化的工作方式。
那么让我们从查询开始,删除ToArray()
的内容:
var query = (from inspArch in inspectionArchives
from inspAuth in inspArch.InspectionAuthority
group new { inspArch, inspAuth } by inspArch.CustomerId into g
select new
{
clientId = g.Key,
id = g.Select(x => x.inspArch.Id),
authId = g.Select(x => x.inspAuth.Id).Distinct()
});
如果你设置了一个断点,你会看到这是一个db - sql查询,也可以通过:
var sqlQuery = query.ToString();
现在唯一剩下的事情是如何实现这些ToArray()
调用的最终投影。从逻辑上讲,第一次尝试应该是:
var result = query
.Select(e => new { e.clientId, id = e.Id.ToArray(), authId = e.authId.ToArray() })
.ToList();
但是结果将是相同的例外,因为EF Linq提供程序足够聪明,可以遍历所有的投影并生成最终的投影。
所以我们需要在做最后的投影之前,具体化查询。不要使用ToList()
或ToArray()
!最便宜的方法是使用ToEnumerable()
,它会给我们一个最小的(单个项目)临时投影内存对象,然后我们将其转换为最终的投影。所以我们最终的(有效的)代码是:
var result = query
.AsEnumerable()
.Select(e => new { e.clientId, id = e.Id.ToArray(), authId = e.authId.ToArray() })
.ToList();
或者把它们放在一起:
var result =
(from inspArch in inspectionArchives
from inspAuth in inspArch.InspectionAuthority
group new { inspArch, inspAuth } by inspArch.CustomerId into g
select new
{
clientId = g.Key,
id = g.Select(x => x.inspArch.Id),
authId = g.Select(x => x.inspAuth.Id).Distinct()
})
.AsEnumerable()
.Select(e => new { e.clientId, id = e.Id.ToArray(), authId = e.authId.ToArray() })
.ToList();
注:使用EF查询时,最好不要在投影中使用ToArray()
。最终使用ToList()
或保持原样(IEnumerable
, IOrderedEnumerable
等)- EF将使用适合的最佳容器为您实现它们(通常是List,这就是为什么ToList()
被识别,而ToArray()
没有)。