我有这个LINQ to entity:
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 Class;有没有办法在这些行上使用提到的DbFunctions类?
id = g.Select(x => x.inspArch.Id).ToArray(),
authId = g.Select(x => x.inspAuth.Id).Distinct().ToArray()
而不是ToArray()方法或其他方法使ToArray()方法可以识别为LINQ to Entities?
答案 0 :(得分:3)
你是如此亲密。这里没有与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();
P.S。使用EF查询时,最好不要在投影中使用ToArray()
。最后使用ToList()
或保持原样(IEnumerable
,IOrderedEnumerable
等) - EF会使用最适合的容器(通常为List,这就是{{1 }}被识别,而ToList()
没有。)