代码之家  ›  专栏  ›  技术社区  ›  Hadi Bawarshi

ASP。NET Core 6 C#基于CreatedDate(DateTime)对数据进行每日、每月、每年分组,导致:无法翻译LINQ表达式

  •  2
  • Hadi Bawarshi  · 技术社区  · 1 年前

    我有一种方法,可以从SQL Server数据库中获取数据,并每天、每月和每年对其进行分组。

    我们目前正在处理至少3000张唱片,而且这个数字每天都在根据销售额增加。

    我正在尝试获取数据并在数据库上进行分组,因为目前在服务器内存上进行分组可能很好,但以后效率会大大降低,但每次尝试时,我都会收到以下错误:

    LINQ表达式'DbSet()\r\n。LeftJoin(\r\ninner:DbSet(),\r\n outerKeySelector:b=>EF。属性<int>(b,“CreatedByBusinessCrewId”),\r\n innerKeySelector:b0=>EF。属性<int>(b0,“Id”),\r\n结果选择器:(o,i)=>新的透明标识符<BusinessSale,BusinessCrew>(\r\n外部=o,\r\n内部=i\r\n))\r\n。其中(b=>b.Outer.BusinessId==__BusinessId_0&&b.Inner.BranchId==__BranchId_1)\r\n。GroupBy(b=>Invoke(__dateTruncateFunction_2,b.Outer.CreateDate.Value)\r\n)'无法翻译。以可翻译的形式重写查询,或者通过插入对“AsEnumerable”、“AsAsyncEnumerable“、“ToList”或“ToListAsync”的调用,显式切换到客户端评估。看见 https://go.microsoft.com/fwlink/?linkid=2101038 了解更多信息。

    这是我的遗珠

    public enum BusinessSalesFilteredBy
    {
        Logs = 0,
        Day = 1,
        Month = 2,
        Year = 3,
    
    }
    

    请注意,我使用的是工作单位。

    这是我的代码:

    var baseQuery = _uow.BusinessSalesRepo.GetAll(sale => sale.BusinessId == BusinessId && sale.CreatedByBusinessCrew.BranchId == BranchId);
    
    salesCount = baseQuery.Count();
    clientsCount = baseQuery.Select(s=> s.ClientProfileId).Distinct().Count();
    sumPurchases = baseQuery.Sum(s=> s.PurchasedAmount ?? 0);
    
     Func<DateTime, DateTime> dateTruncateFunction;
    
        switch (filterBy)
        {
            case (int)BusinessSalesFilteredBy.Day:
                groupKeySelector = sale=> sale.CreateDate.Value.Date;
                break;
            case (int)BusinessSalesFilteredBy.Month:
                groupKeySelector = sale=> new DateTime(sale.CreateDate.Value.Year,   checkin.CreateDate.Value.Month, 1);
                break;
            case (int)BusinessSalesFilteredBy.Year:
                groupKeySelector = sale=> new DateTime(sale.CreateDate.Value.Year, 1, 1);
                break;
            default:
                // Default to daily grouping
                groupKeySelector = sale=> sale.CreateDate.Value.Date;
                break;
        }
    
        // Now, calculate the summary data with date truncation
    var summaryQuery = baseQuery
    .GroupBy(sale=> dateTruncateFunction(sale.CreateDate.Value))
                            .Select(grouped => new
                            {
                                SalesOn = grouped.Key,
                                SalesCount = grouped.Count(),
                                ClientCount = grouped.Select(x =>    x.ClientProfileId).Distinct().Count(),
                                SumPurchases = grouped.Sum(x => x.PurchasedAmount ?? 0)
                            });
    var pagedSummary = await summaryQuery.ToListAsync();
    

    最后是 GetAll() 方法:

    public IQueryable<T> GetAll(Expression<Func<T, bool>> predicate)
    {
        return GetAll().Where(predicate);
    }
    
    public IQueryable<T> GetAll()
    {
        return _context.Set<T>().AsNoTracking();
    }
    

    我的问题是,我如何在数据库端执行整个操作,而不将数据带入内存,希望这是最有效的方法。

    难道没有内置的东西可以帮助LINQ查询中的DateTime翻译吗?

    0 回复  |  直到 1 年前
        1
  •  1
  •   Svyatoslav Danyliv    1 年前

    你必须使用 Expression<Func<,>> 以使事情在服务器端工作。已添加 DateGroupingKey ,不确定EF将如何治疗 DateTime 作为分组密钥。

    class DateGroupingKey
    {
        public int Year [ get; set; ]
        public int Month [ get; set; ]
        public int Day [ get; set; ]
    }
    
    var baseQuery = _uow.BusinessSalesRepo
        .GetAll(sale => sale.BusinessId == BusinessId && sale.CreatedByBusinessCrew.BranchId == BranchId);
    
    
    Expression<Func<DateTime, DateGroupingKey>> groupKeySelector;
    
    switch (filterBy)
    {
        case (int)BusinessSalesFilteredBy.Month:
            groupKeySelector = sale => new DateGroupingKey { 
                Year = sale.CreateDate.Value.Year, Month = sale.CreateDate.Value.Month 
            }
            break;
        case (int)BusinessSalesFilteredBy.Year:
            groupKeySelector = sale => new DateGroupingKey { 
                Year = sale.CreateDate.Value.Year 
            }
           break;
        default:
            // Default to daily grouping
            groupKeySelector = sale => new DateGroupingKey { 
                Year = sale.CreateDate.Value.Year, Month = sale.CreateDate.Value.Month, Day = sale.CreateDate.Value.Day 
            }
    
          break;
    }
    
    ar summaryQuery = baseQuery
        .GroupBy(groupKeySelector)
        .Select(grouped => new
        {
            SalesOn = grouped.Key,
            SalesCount = grouped.Count(),
            ClientCount = grouped.Select(x => x.ClientProfileId).Distinct().Count(),
            SumPurchases = grouped.Sum(x => x.PurchasedAmount ?? 0)
        });
    var pagedSummary = await summaryQuery.ToListAsync();