计一次EF Core优化中使用GroupBy的囧事

有这个么一个需求,要求通过业务员的邮件查询CRM当前业务员的订单下的客户信息及该客户下的虚拟充值码和对应充值号,表结构有用户表,订单表,客户表,产品合同表,产品详情表,结构如下:

计一次EF Core优化中使用GroupBy的囧事

通过业务员Id查询订单表,查出改业务员的所有订单,一个客户有多个订单,一个订单有多个产品,产品详情和产品表是一对一的关系,就是一个客户下有多个产品。.

第一个方案是,用Groupby先查出所有的客户信息,然后循环查询合同和产品表。如下:

var appcustomer = orders
    .Join(_context.CustomerQuery, c => c.cuId, d => d.Id, (c, d) => new { name = d.CuName, credit_code = d.CuNameCode, code = d.CuCode, d.Id, d.ASTID })
    .GroupBy(g => new { g.name, g.code, g.credit_code, g.Id, g.ASTID })
    .Select(s => new { name = s.Key.name, code = s.Key.code, credit_code = s.Key.credit_code, Id = s.Key.Id, ASTID = s.Key.ASTID }).ToList();

foreach (var item in appcustomer)
{
    CustomerOupPut oupPut = new Customer();
    oupPut.name = item.name;
    oupPut.code = item.code;
    oupPut.credit_code = item.credit_code;

    // 查询客户后获取客户相关的充值码 填充至 BrandRegNos
    var regOrders = _context.OrderQuery.Where(w => w.cuId== item.Id)
    .Join(_context.R_Order_PruductQuery.Where(w => w.Status != 2), a => a.Id, b => b.OrderID, (a, b) => new { b.InfoID });
    var BrandRegNos = _context.PruductInfoQuery.Where(w => !string.IsNullOrEmpty(w.BrandRegNo))
    .Join(regOrders, a => a.Id, b => b.InfoID, (a, b) => new { BrandRegNo = a.BrandRegNo, NoId= a.NoId})
    .Select(s => s.BrandRegNo.Trim() + ":" + s.NoId).ToList();
    oupPut.BrandRegNos = BrandRegNos;
    list.Add(oupPut);
}

if (list.Count > 0)
    result.Data = list;
else
    result.Content = "无数据!";

查询结果30S,速度奇慢。接口使用反馈过来了,说查询太慢,但是查看语句无从下手,于是请教了同事,同事给我的意见是Groupby 后循环直接循环订单对象,我没有明白。最后同事给我写了案例,才发现Groupby可以这么用,在Groupby后不但可以拿到分组的对象,还可以拿到查询的集合,代码如下。

var Ordercus = orders.Select(s => new Order {Id=s.Id, CuId=s.CuId})
 .AsEnumerable().GroupBy(g=>g.CuId.Value).ToList();
foreach (var item in Ordercus )

   var appusers = _context.CustomerQuery.Where(w => w.Id == item.Key).FirstOrDefault();
   
   if (appusers != null)
   {
     CustomerOupPut oupPut = new Customer();
    oupPut.name = item.name;
    oupPut.code = item.code;
    oupPut.credit_code = item.credit_code;
     
           brandRegsOupPut.BrandRegNos = new List<string>();
           foreach (var order in item)
           {
               var BrandRegNos =  _context.R_Order_PruductQuery
               .Where(w.OID == order.Id )
               .Join( _context.PruductInfoQuery, a => a.InfoID, b => b.Id, (a, b) => new { b.BrandRegNo,b.NoId}).ToList();
               BrandRegNos.ForEach(BrandRegNo => {
                   if (!string.IsNullOrEmpty(BrandRegNo.BrandRegNo )) { brandRegsOupPut.BrandRegNos.Add(BrandRegNo.BrandRegNo.Trim() + ":" + BrandRegNo.NoId); }
               });
           }
  }

这样查询速度提高到3s,完美。就是感觉比较囧。使用linq语句不能按照SQL的思维,多查查官方的文档,根据文档举一反三才能提高水平。