在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:无法转换LINQ表达式
'DbSet<HistoryEntity> .GroupBy( source: h => copyOfStruct => copyOfStruct.Date.Invoke(h.Timestamp), keySelector: h => h)'
。可以以可翻译的形式重写查询,也可以通过插入对AsEnumerable(),AsAsyncEnumerable(),ToList()或ToListAsync()的调用来显式切换到客户端评估。
如何按日期分组?
答案 0 :(得分:5)
因此在C#中,当您使用LINQ-to-SQL 查询时,您正在使用IQueryable<T>
上的扩展方法。如果我们看一下GroupBy
method的签名,您会发现函数签名实际上是
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#具有自己的查询理解builder for SQL。它使您可以编写类似于seq
的计算表达式,以转换为SQL查询。这就像您期望的那样工作。
query {
for record in db do
select record
}
答案 1 :(得分:0)
在查询表达式中使用时,按.Date
分组。
query {
for h in db.History do
groupValBy h h.Timestamp.Date into g
select {
Date = g.Key
Count = g.Count()
}
}
从here被盗的代码。
如果有人可以解释为什么查询表达式起作用但LINQ版本不起作用,我将不胜感激:)