groupby在F#3.0查询中的多个列

Jiz*_*ugu 37 f# f#-3.0

只需尝试F#3.0,就多列分组而言,只需要花一点时间.显而易见的是

query {
    for d in context.table do
    groupBy (d.col1,d.col2) into g
    select (g.Key)
}
Run Code Online (Sandbox Code Playgroud)

但是我得到了"LINQ to Entities中只支持无参数构造函数和初始值设定项".例外.

我似乎无法在msdn上找到一个例子

http://msdn.microsoft.com/en-us/library/hh225374(v=vs.110).aspx

http://msdn.microsoft.com/en-us/library/hh361035(v=vs.110).aspx

而且我意识到我的问题类似于" F#中的实体框架和匿名类型 ",但它似乎是专注于powerpack/F#2.x而且我希望F#3.0有一个优雅的答案......任何想法?

更新:

我在阅读Brian的帖子时遇到了CLIMutable属性:

http://blogs.msdn.com/b/fsharpteam/archive/2012/07/19/more-about-fsharp-3.0-language-features.aspx

我很乐观,所以我试过了

[<CLIMutable>]
type MyRecord = { Column1 : int; Column2 : int }

query {
    for d in context.table do
    groupBy {Column1 = col1; Column2 = col2} into g
    select (g.Key)
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,我得到完全相同的例外.

Pau*_*ott 4

以下是在 c# 中用于分组并转换为 f# 的多列示例(过于偏执的管理使我重命名了所有内容,但我相信我一直保持一致):

(数据库由SqlMetal生成,GetSummedValuesResult是F#记录类型)

C#

public static class Reports
{
    public static IReadOnlyList<GetSummedValuesResult> GetSummedValues(TheDatabase db, DateTime startDate, DateTime? endDate)
    {
        var query =
            from sv in db.SomeValues

            where (sv.ADate >= startDate && sv.ADate <= (endDate ?? startDate))

            group sv by new { sv.ADate, sv.Owner.Name } into grouping

            select new GetSummedValuesResult(
                grouping.Key.ADate,
                grouping.Key.Name,
                grouping.Sum(g => g.Value)
            );

        return query.ToList();
    }
}
Run Code Online (Sandbox Code Playgroud)

F#

type Reports() =
    static member GetSummedValues (db:TheDatabase) startDate (endDate:Nullable<DateTime>) =
        let endDate = if endDate.HasValue then endDate.Value else startDate

        let q = query {
            for sv in db.SomeValues do
            where (sv.ADate >= startDate && sv.ADate <= endDate)

            let key = AnonymousObject<_,_>(sv.ADate, sv.Owner.Name)
            groupValBy sv key into grouping

            select {
                ADate        = grouping.Key.Item1;
                AName        = grouping.Key.Item2;
                SummedValues = grouping.Sum (fun (g:TheDatabaseSchema.SomeValues) -> g.Value)
            }
        }

        List(q) :> IReadOnlyList<GetSummedValuesResult>
Run Code Online (Sandbox Code Playgroud)

所以要使用的是Microsoft.FSharp.Linq.RuntimeHelpers.AnonymousObject

请注意,您不应该将 Seq 模块用于聚合函数!

SummedValues  = grouping |> Seq.sumBy (fun g -> g.SomeValues)
Run Code Online (Sandbox Code Playgroud)

虽然这可行,但它在客户端进行聚合,而不是制定适当的 SQL。