.net EF查询中TotalMinutes功能的解决方案?

ruyhziif  于 2023-01-06  发布在  .NET
关注(0)|答案(1)|浏览(114)

我有以下疑问。

var query = DbContext.Trucks
    .Where(t => t.Facility.Company.CompanyCode == companyCode)
    .Where(t => t.Departure >= startMonth && t.Departure < endMonth);

if (customerId.HasValue)
    query = query.Where(t => t.PurchaseOrder.CustomerId == customerId);

var results = await query.GroupBy(t => new { t.Departure!.Value.Year, t.Departure!.Value.Month })
    .Select(g => new
    {
        Month = new DateTime(g.Key.Year, g.Key.Month, 1),
        Dwell = g.Average(t => (t.Departure!.Value - t.Arrival).TotalMinutes)
    })
    .ToDictionaryAsync(g => g.Month, g => g.Dwell);

当前查询失败。

The LINQ expression 'GroupByShaperExpression:
KeySelector: new { 
    Year = DATEPART(year, t.Departure), 
    Month = DATEPART(month, t.Departure)
 }, 
GroupingEnumerable:ShapedQueryExpression: 
    QueryExpression: 
        Projection Mapping:
            Outer.Outer -> EntityProjectionExpression: Truck
            Outer.Inner -> EntityProjectionExpression: Facility
            Inner -> EntityProjectionExpression: Company
        SELECT 1
        FROM Trucks AS t
        INNER JOIN Facilities AS f ON t.FacilityId == f.Id
        INNER JOIN Companies AS c ON f.CompanyId == c.Id
        WHERE ((c.CompanyCode == @__companyCode_0) && ((t.Departure >= @__startMonth_1) && (t.Departure < @__endMonth_2))) && ((DATEPART(year, t.Departure) == DATEPART(year, t.Departure)) && (DATEPART(month, t.Departure) == DATEPART(month, t.Departure)))
    ShaperExpression: new TransparentIdentifier<TransparentIdentifier<Truck, Facility>, Company>(
            Outer = new TransparentIdentifier<Truck, Facility>(
                Outer = EntityShaperExpression: 
                    PegasusEntities.Models.Truck
                    ValueBufferExpression: 
                        ProjectionBindingExpression: Outer.Outer
                    IsNullable: False
                , 
                Inner = EntityShaperExpression: 
                    PegasusEntities.Models.Facility
                    ValueBufferExpression: 
                        ProjectionBindingExpression: Outer.Inner
                    IsNullable: False
            ), 
            Inner = EntityShaperExpression: 
                PegasusEntities.Models.Company
                ValueBufferExpression: 
                    ProjectionBindingExpression: Inner
                IsNullable: False
        )

    .AsQueryable()
    .Average(e => (e.Outer.Outer.Departure.Value - e.Outer.Outer.Arrival).TotalMinutes)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.

我相信我已经将问题隔离到了TimeSpan.TotalMinutes(在Dwell的赋值语句中),它显然不能转换为SQL。
除了要求微软增加对它的支持外,有没有人想出了一个解决办法?在客户端运行这个程序需要下载一大堆我不需要的数据。

0tdrvxhp

0tdrvxhp1#

对于SQL Server,您可以使用EF.Functions.DateDiffMinute
即变化

(t.Departure!.Value - t.Arrival).TotalMinutes

变成了

EF.Functions.DateDiffMinute(t.Arrival, t.Departure.Value)

请注意,DATEDIFF计算边界跨越,而TimeSpan. TotalMinutes类似于TimeSpan. TotalSeconds/60。因此,自动将TimeSpan. TotalMinutes转换为DateDiffMinute是危险的。如果这是所需的输出,您可以使用如下代码:

EF.Functions.DateDiffSecond(t.Arrival, t.Departure.Value) / 60.0

其他数据库处理这种情况的方式不同。例如Oracle和我认为Postgres允许在SQL中使用日期时间算法,因此允许您简单地减去日期。所以答案确实取决于提供商。

相关问题