c# - 如何在 LINQ 中使用 DbFunctions?

标签 c# linq-to-entities dbfunctions

我有这个 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 Class ;有没有办法在这些行上使用提到的 DbFunctions 类?

id = g.Select(x => x.inspArch.Id).ToArray(),               
authId = g.Select(x => x.inspAuth.Id).Distinct().ToArray()

代替 ToArray() 方法或其他方法使 ToArray() 方法可被 LINQ to Entities 识别?

最佳答案

你很亲近。此处与 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() 或保持原样(IEnumerableIOrderedEnumerable 等)- EF 将使用最佳容器为您实现它们适合(通常是列表,这就是为什么 ToList() 被识别,而 ToArray() 不被识别)。

关于c# - 如何在 LINQ 中使用 DbFunctions?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33048055/

相关文章:

vb.net - DbFunctions.TruncateTime 在不同服务器时区的行为是否不同?

c# - LinqPad 5 : The name 'DbFunctions' does not exist in the current context

c# - 如何在另一个文本字段中查看一个文本字段中的文本?

c# - 为什么在检查 null 后需要显式转换?

c# - 使用 LINQ to Entities 更新数据库

c# - 无法将类型 'System.Int32' 转换为类型 'System.Object'。 LINQ to Entities 仅支持转换实体数据模型基元类型

c# - 具有日期范围的 Linq 查询不返回任何记录?

c# - Visual Studio不会复制间接引用的项目中的内容文件

c# - 过滤 GroupJoin 查询

c# - 如何在经典 .NET 的 EF 6 Code First 中使用 SQL Server JSON_VALUE 函数