温馨提示:本文翻译自stackoverflow.com,查看原文请点击:linq - Entity Framework Core GroupBy Date
entity-framework-core f# linq

linq - Entity framework 核心组截止日期

发布于 2020-04-04 10:49:57

在C#中,您可以按.Date以下方式分组

db.History.GroupBy(x => x.Timestamp.Date)
          .Select(g => new { key = g.Key, aggregate = g.Count() })

但是,等效的F#不起作用:

db.History.GroupBy(fun x -> x.Timestamp.Date)
          .Select(fun g -> { Date = g.Key; Count = g.Count()} )

相关记录:

type DateCount = {
    Date: DateTime
    Count: int
}

它引发以下错误:

System.InvalidOperationException:'DbSet<HistoryEntity> .GroupBy( source: h => copyOfStruct => copyOfStruct.Date.Invoke(h.Timestamp), keySelector: h => h)'无法转换LINQ表达式以可以翻译的形式重写查询,或者通过插入对AsEnumerable(),AsAsyncEnumerable(),ToList()或ToListAsync()的调用来显式切换到客户端评估。

如何按日期分组?

查看更多

提问者
DharmaTurtle
被浏览
96
Asti 2020-02-02 13:07

因此,在C#中,当您使用LINQ-to-SQL 查询时,您正在使用上的扩展方法IQueryable<T>如果我们看一下再说的签名,该GroupBy 方法,你会看到,函数签名实际上是

IQueryable<TSource>.GroupBy<TSource,TKey>(Expression<Func<TSource,TKey>> keySelector)

这是怎么回事?Expression<>是一种特殊类型-当C#编译器发现一种Expression<>类型时,编译器将构建AST,并传递AST对象(类型为Expression<Func<>>),而不是通常的委托。底层函数将检查AST并构建最终需要的查询表达式,例如用于查询数据库的SQL。

您可以自己尝试:

Expression<Func<int>> getRandom = () => 4; //random, chosen by fair dice roll

您可以检查的属性getRandom以查看AST。由于魔术发生在C#编译器中,因此当您在F#中进行操作时,这不会消除它。

要更详细地讲,F#编译器可以识别Expression<>,但是可以通过应用隐式F#引用来识别,因此您将获得F#引用包装的方法调用,该方法调用将转换为C#表达式树。(很抱歉,那是继续进行。)

F#有自己的SQL查询理解生成它使您可以编写类似于seq可转换为SQL查询的计算表达式这就像您期望的那样工作。

query {
    for record in db do
    select record
}