ASP.NET Core 6 C# 根据 CreatedDate(DateTime) 对每日、每月、每年的数据进行分组,导致:无法转换 LINQ 表达式

ASP.NET Core 6 C# Grouping Data Daily ,Monthly ,Yearly based on CreatedDate(DateTime) causing : The LINQ expression could not be translated

提问人:Hadi Bawarshi 提问时间:10/18/2023 最后编辑:marc_sHadi Bawarshi 更新时间:10/18/2023 访问量:57

问:

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

我们目前正在处理至少 3k 条记录,并且这个数字每天都会根据销售额增加。

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

LINQ 表达式 'DbSet()\r\n.LeftJoin(\r\ninner: DbSet(), \r\n outerKeySelector: b => EF.Property<int?>(b, “CreatedByBusinessCrewId”), \r\n innerKeySelector: b0 => EF.Property<int?>(b0, “Id”), \r\n resultSelector: (o, i) => new TransparentIdentifier<BusinessSale, BusinessCrew>(\r\n Outer = o, \r\n Inner = 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转换?

C# asp.net LINQ 实体框架核心 net-6.0

评论

0赞 Basil Kosovan 10/18/2023
这回答了你的问题吗?使用 IMethodCallTranslator 编写自定义实体框架函数

答:

1赞 Svyatoslav Danyliv 10/18/2023 #1

你必须使用才能使事情在服务器端工作。已添加,不确定 EF 将如何将其视为分组键。Expression<Func<,>>DateGroupingKeyDateTime

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();

评论

0赞 Steve Py 10/18/2023
这应该差不多了。主要问题是 GroupBy 需要一个 ,而不是一个,那么表达式中的另一个问题将是使用它不能转换为 SQL,需要用于按日期分组,忽略时间。ExpressionFuncsale.CreatedDate.Value.Datenew DateTime(sale.CreatedDate.Value.Year, sale.CreatedDate.Value.Month, sale.CreatedDate.Value.Day)