C# 如何在LINQ中使用DBFunction?
我有一个LINQ to实体:C# 如何在LINQ中使用DBFunction?,c#,linq-to-entities,dbfunctions,C#,Linq To Entities,Dbfunctions,我有一个LINQ to实体: var result = (from inspArch in inspectionArchives from inspAuth in inspArch.InspectionAuthority group new { inspArch, inspAuth } by inspArch.CustomerId into g select new {
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类
id = g.Select(x => x.inspArch.Id).ToArray(),
authId = g.Select(x => x.inspAuth.Id).Distinct().ToArray()
取而代之的是ToArray()方法,或者是另一种使ToArray()方法可被LINQ识别为实体的方法?你太接近了。这里没有与
DbFunctions
相关的内容,您只需要说明查询具体化是如何工作的
因此,让我们从查询开始,删除ToArray()
stuff:
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
,IORDerenumerable
等)-EF将使用最合适的容器为您具体化它们(通常是列表,这就是为什么ToList()
被识别,而ToArray()
不被识别的原因)。它工作正常,但是,它将整个表格拉入内存,然后应用投影…不是很有效。-您是否通过分析进出数据库的流量来验证这一点?在.ToList()
之前的每个部分(包括投影)都被转换为SQL。也许你的意思是说,ToList
在内存中构建了一个实际上并不需要的结果?如果是这样,只需使用AsEnumerable()
即可防止这种情况。为什么在最终结果中使用数组如此重要?