C# groupby 使用 AsQueryable 报错

Posted

技术标签:

【中文标题】C# groupby 使用 AsQueryable 报错【英文标题】:Error report of C # groupby using AsQueryable 【发布时间】:2021-07-19 06:20:55 【问题描述】:
var commodity = _appDbContext.ArchivesCCommodity.Where(lambda)
          .GroupJoin(_appDbContext.ArchivesCCommoditySpecification, a => a.Code, b => b.Commodity, (a, b) => new  a, b )
          .SelectMany(a => a.b.DefaultIfEmpty(), (a, b) => new  a.a, b )
          .GroupJoin(_appDbContext.ArchivesCSpecificationDetail, a => a.a.a.b.SpecificationDetail, d => d.Code, (a, d) => new  a, d )
          .SelectMany(a => a.d.DefaultIfEmpty(), (a, d) => new
          
              Commodity = a.a.a.Code,
              CommodityName = a.a.a.Name,
              SpecificationDetailName = d.Name,
              OrderSN = d.OrderSN
          ).AsQueryable().OrderBy(a => a.OrderSN).GroupBy(a => new  a.Commodity, a.CommodityName )
           .Select(a => new
           
               Commodity = a.Key.Commodity,
               CommodityName = a.Key.CommodityName,
               SpecificationDetailName = string.Join(" - ", a.Select(a => a.SpecificationDetailName)),
               SpecificationDetailTotal = string.Join(" - ", a.Select(a => a.SpecificationDetailName)) == "" ? 0 : a.Count()
           ); 

.AsQueryable() 会导致错误的地方

.AsQueryable()
.OrderBy(a => a.OrderSN)
.GroupBy(a => new  a.Commodity, a.CommodityName )

改成AsEnumerable()不会报错

.ASEnumerable()
.OrderBy(a => a.OrderSN)
.GroupBy(a => new  a.Commodity, a.CommodityName )

但是我暂时不想把这段代码发送到数据库,因为它会在分页查询之后发送。不知道怎么处理?

////////////我贴了我的完整代码,讲了我的实际需求

查询代码,逐页查询数据库。例如,只检查一页和 10 行记录。这里没问题。

            var AA= _appDbContext.ArchivesCCommodity.Where(lambda)
              .GroupJoin(_appDbContext.ArchivesCCommoditySpecification, a => a.Code, b => b.Commodity, (a, b) => new  a, b )
              .SelectMany(a => a.b.DefaultIfEmpty(), (a, b) => new  a.a, b )
              .GroupJoin(_appDbContext.ArchivesCSpecificationDetail, a => a.a.b.SpecificationDetail, d => d.Code, (a, d) => new  a, d )
              .SelectMany(a => a.d.DefaultIfEmpty(), (a, d) => new
              
                  Commodity = a.a.a.a.a.Code,
                  CommodityName = a.a.a.a.a.Name,
                  SpecificationDetailName = d.Name,
                  OrderSN = d.OrderSN
              );

            PageHealper<object> page = new PageHealper<object>();

            page.Start(pageNum, pageSize);

            page = await page.RestPage(AA);

这时候我又分组排序了,现在发现:

    不是操作分页查询结果,而是查询所有AA数据库。 根据前面的分页查询,得到行数和页码。在这里,通过分组和合并来改变行数。 这就是为什么我想将分组和排序放在一起,最后是分页。
  var BB = AA.AsEnumerable().OrderBy(a => a.OrderSN).GroupBy(a => new  a.Commodity, a.CommodityName, a.Specification, a.SpecificationName )
               .Select(a => new
               
                   Commodity = a.Key.Commodity,
                   CommodityName = a.Key.CommodityName,
                   SpecificationDetailName = string.Join(" - ", a.Select(a => a.SpecificationDetailName)),
                   SpecificationDetailTotal = string.Join(" - ", a.Select(a => a.SpecificationDetailName)) == "" ? 0 : a.Count()
               ); ;

            page.Data = BB.ToList<object>();
            return page;

【问题讨论】:

.AsQueryable() 有用的情况很少。为什么你认为它在这里有用? 一个鲜为人知的事实是,框架中的GroupBy在内存中进行了很好的更改。当您调用 .AsQueryable() 时,它可能已经访问了数据库。 另外,作为一个小提示,Commodity = a.a.a.Code, 并不是世界上最好的命名。祝你好运,几天后记住这些不同的as 的含义。 你试过删除所有的 As... 吗?只需 SelectMany().OrderBy() @cheny,试过了,错了 【参考方案1】:

查看这篇文章https://weblogs.asp.net/zeeshanhirani/using-asqueryable-with-linq-to-objects-and-linq-to-sql,了解 AsQueryable 的作用。

我认为您在那里并不真的需要 AsQueryable...LINQ to SQL 不喜欢该查询的某些内容。

它不喜欢 String.Join(...) 因为它不能翻译它。

因此,您可以做的一件事是将 .AsEnumerable() 放在 GroupBy() 之后,这将在 SQL 中执行所有操作,在内存中执行所有操作。

例如:

var commodity = _appDbContext.ArchivesCCommodity.Where(lambda)
        .GroupJoin(_appDbContext.ArchivesCCommoditySpecification, a => a.Code, b => b.Commodity, (a, b) => new  a, b )
        .SelectMany(a => a.b.DefaultIfEmpty(), (a, b) => new  a.a, b )
        .GroupJoin(_appDbContext.ArchivesCSpecificationDetail, a => a.a.a.b.SpecificationDetail, d => d.Code, (a, d) => new  a, d )
        .SelectMany(a => a.d.DefaultIfEmpty(), (a, d) => new
        
            Commodity = a.a.a.Code,
            CommodityName = a.a.a.Name,
            SpecificationDetailName = d.Name,
            OrderSN = d.OrderSN
        ).OrderBy(a => a.OrderSN).GroupBy(a => new  a.Commodity, a.CommodityName )
        .AnEnumerable()
        .Select(a => new
        
            Commodity = a.Key.Commodity,
            CommodityName = a.Key.CommodityName,
            SpecificationDetailName = string.Join(" - ", a.Select(a => a.SpecificationDetailName)),
            SpecificationDetailTotal = string.Join(" - ", a.Select(a => a.SpecificationDetailName)) == "" ? 0 : a.Count()
        ); 

【讨论】:

我想得到的是整个查询没有到达数据库,直到后面的分页查询才到达数据库。 如果您希望查询稍后运行,那么您可以稍后将其放入您的代码中。或者您可以将查询分成两部分,一部分在 AsEnumerable() 之前,另一部分在之后,并且不要调用 AsEnumerable(),直到您希望针对数据库编译和执行查询,然后一旦查询针对数据库运行,稍后在您的代码,添加查询的第二部分,它将在内存中执行“选择”。

以上是关于C# groupby 使用 AsQueryable 报错的主要内容,如果未能解决你的问题,请参考以下文章

linq中AsEnumerable和AsQueryable的区别

linq中AsEnumerable和AsQueryable的区别

如何使用 LINQ 的 AsQueryable() 从 MongoDB 的内部数组中获取数据?

LINQ语句中的.AsEnumerable() 和 .AsQueryable()的区别

AsQueryable() 的目的是啥?

AsQueryable() 返回用户未处理的 NullReference 异常“对象引用未设置为对象实例”