客户端评估efcore后无法处理集合操作

问题描述 投票:0回答:5

Ef Core 接收错误

System.InvalidOperationException:无法在之后处理集合操作 客户评价,考虑将操作移到最后一个之前 Select() 调用(请参阅问题 #16243): Microsoft.EntityFrameworkCore.Query.SqlExpressions.SelectExpression.ApplySetOperation(SetOperationType setOperationType、SelectExpression select2、布尔值不同)

执行时

 public async Task<object> GetUnitsForDataTableAsync() =>
        
            await context.Units
             .Where(x => !x.TractUnitJunctions.Any())
              .Select(x => new
              {
                  x.Id,
                  x.UnitName,
                  x.UnitAcres,
                  TractNum = String.Empty,
                  Wells = String.Empty,
                  NumOfWells = 0,
              })
              .Union(
                        context.TractUnitJunctions
                        .Select(x => new
                         {
                            Id = x.UnitId,
                            x.Unit.UnitName,
                            x.Unit.UnitAcres,
                            x.Tract.TractNum,
                            Wells = string.Join(", ", x.TractUnitJunctionWellJunctions
                                              .Select(z => $"{z.Well.WellNum} ({z.Well.ApiNum})")
                                        ),
                            NumOfWells = x.TractUnitJunctionWellJunctions.Count()
                 }))
                .ToListAsync().ConfigureAwait(false);

但是,如果我将其分成两个查询,该函数就可以正常工作。

 public async Task<object> GetUnitsForDataTableAsync()
        {
            var List1 = await context.Units
             .Where(x => !x.TractUnitJunctions.Any())
              .Select(x => new
              {
                  x.Id,
                  x.UnitName,
                  x.UnitAcres,
                  TractNum = String.Empty,
                  Wells = String.Empty,
                  NumOfWells = 0,
              })
             .ToListAsync().ConfigureAwait(false);

            var List2 = await context.TractUnitJunctions
                 .Select(x => new
                 {
                     Id = x.UnitId,
                     x.Unit.UnitName,
                     x.Unit.UnitAcres,
                     x.Tract.TractNum,
                     Wells = string.Join(", ", x.TractUnitJunctionWellJunctions
                                              .Select(z => $"{z.Well.WellNum} ({z.Well.ApiNum})")
                                        ),
                     NumOfWells = x.TractUnitJunctionWellJunctions.Count()
                 })
                .ToListAsync().ConfigureAwait(false);


            return List1.Concat(List2);
        }

我已经研究了这个错误,但我不确定如何重构第一个查询来解决该错误

c# .net-core entity-framework-core
5个回答
5
投票

在工作时接受的答案是有缺陷的,因为你急于加载第一个列表。

这是一个已知的错误,您应该能够通过将 Where 子句移到 Union 之后来解决

如此处讨论https://github.com/dotnet/efcore/issues/16243#issuecomment-622452276


3
投票

.AsEnumerable()
解决问题之前为第一个查询添加
.Union

如下

public async Task<object> GetUnitsForDataTableAsync() =>
    
        await context.Units
         .Where(x => !x.TractUnitJunctions.Any())
          .Select(x => new
          {
              x.Id,
              x.UnitName,
              x.UnitAcres,
              TractNum = String.Empty,
              Wells = String.Empty,
              NumOfWells = 0,
          }).AsEnumerable()
          .Union(
                    context.TractUnitJunctions
                    .Select(x => new
                     {
                        Id = x.UnitId,
                        x.Unit.UnitName,
                        x.Unit.UnitAcres,
                        x.Tract.TractNum,
                        Wells = string.Join(", ", x.TractUnitJunctionWellJunctions
                                          .Select(z => $"{z.Well.WellNum} ({z.Well.ApiNum})")
                                    ),
                        NumOfWells = x.TractUnitJunctionWellJunctions.Count()
             }))
            .ToListAsync().ConfigureAwait(false);

1
投票

这是 EF Core 的限制,我认为它永远不会得到解决。 第一个列表很容易转换为 SQL,但第二个列表是带有客户端评估部分的急切加载查询,您不能将其与 Concat 函数一起使用。因此,您必须运行两个查询并在客户端进行联合。

无论如何,这个查询可以很容易地由 SQL 编写(取决于方言),无需 Concat 和预加载。或者通过带有适当扩展的 LINQ(将根据要求提供解决方案)


0
投票

问题描述: 当部分查询需要运行 C# 代码(显然该代码未在数据库上运行)时,会导致此问题。 因此,如果您需要合并 2 组数据,则两者都需要能够完全完成数据库本身需要执行的所有操作。 您不能让一个查询在执行查询后在 C# 中执行某些功能,然后再次在 SQL 中联合它。 通常,当您不执行联合时,这不是问题,因为 c# 仅在从数据库返回的数据上运行,但如果您使用联合,则不再可能。

要调试 c# 与 SQL 中到底评估了什么,请在并集之前运行前半部分,并获取为该半部分生成的 SQL,然后将 SQL 与 c# 进行比较,看看是否有任何步骤或转换(例如某种类型)字符串操作不是在 SQL 中完成,而是在 C# 中查看结果时完成。然后重写您的查询,以便在联合发生之前不需要在 C# 中执行任何操作。

对查询的第二部分或也需要添加并集的任何其他部分执行相同的操作。

就OP而言,问题是,他试图合并的2个查询来自2个不同的数据库上下文,因此根据代码,它是2个不同的数据库。您无法在数据库级别合并来自不同数据库的 2 个数据集。因为一个数据库将无法访问另一个数据集。

要解决这个问题,你必须确保一切都在那里


-1
投票

使用 LINQ to SQL let 关键字
今天我也遇到这样的问题,是这样解决的! 你可以尝试这样改变它:

    (from u in context.Units
    let TractNum= String.Empty
    let Wells = String.Empty  
    let NumOfWells = 0
    select new 
    {
       u.Id,
       u.UnitName,
       u.UnitAcres,
       TractNum 
       Wells
       NumOfWells
    }).union(
    from u in context.Units
    let TractNum= String.Empty
    let Wells = String.Empty  
    let NumOfWells = 0
    select new 
    {
       u.Id,
       u.UnitName,
       u.UnitAcres,
       TractNum 
       Wells
       NumOfWells
    }
    )
© www.soinside.com 2019 - 2024. All rights reserved.