F#3.0を試して、複数の列でグループ化することになると、ちょっとした壁に突き当たるだけです。明白なことは試したことでした
query {
for d in context.table do
groupBy (d.col1,d.col2) into g
select (g.Key)
}
しかし、「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)
}
残念ながら私はまったく同じ例外を受けます。
以下は、c#でのグループ化に使用され、f#に変換された複数の列の例です(過度に妄想的な管理によってすべての名前が変更されましたが、一貫していたと思います)。
(TheDatabaseは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();
}
}
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>
だから使うものはMicrosoft.FSharp.Linq.RuntimeHelpers.AnonymousObject
集約関数にSeqモジュールを使うべきではないことに注意してください。
SummedValues = grouping |> Seq.sumBy (fun g -> g.SomeValues)
これは機能しますが、適切なSQLを定式化するのではなく、クライアント側で集計を行います。
私はあなたのリンクの最初にこれを見ます、私はそれがあなたが望むものであると思います:
query {
for student in db.Student do
groupValBy student.Name student.Age into g
select (g, g.Key, g.Count())
}
student.Age
。最初の引数groupValBy
格納される値です。2番目はグループ化するためのキーです。言葉を想像してみてby
1番目と2番目の引数の間 - latkin
groupByを使用するときは、集計関数(count、sum、avgなど)を選択する必要があります。
まず、クエリが実際のクエリに変換されることを覚えておく必要があります。SQL
ある時点で。 linqは複数のグループキーの使用をサポートしていないようです。Tuple<>
。したがって、への変換はTuple<>
データベース呼び出しが完了した後に実行する必要があります。
第二に、あなたは達成することができるはずです複数キーのグループ化それぞれのキーで互いに背後にある複数のグループ化を実行することによって:
query {
for d1 in context.table do
groupBy d1.col1 into g1
for d2 in g1 do
groupBy d2.col2 into g2
select g2
}
F#は私の母国語ではないので構文が100%ではない場合は、私と憐れんでください:)ただし、この概念はうまく機能するはずです。
open Microsoft.FSharp.Linq.RuntimeHelpers
open System.Linq
query {
for d in context.table do
let t = MutableTuple<_,_>(Item1=d.col1,Item2=d.col2)
groupValBy d t into g
select (g.Key,g.Count())
}
//in F# 3.0
open Microsoft.FSharp.Linq.RuntimeHelpers
open Microsoft.FSharp.Linq.RuntimeHelpers.LeafExpressionConverter
open System.Linq
//[<CLIMutable>]
//type MyRecord = { Column1 : int; Column2 : int }
// require constructor in F#
// groupBy is not valid
type T(column1 : int, column2 : int)
member val Colum1=colum1 with get,set
membre val Colum2=colum2 with get,set
query {
for d in context.table do
groupValBy d (NewAnonymousObjectHelper(T(d.Colum1,d.Colume2))) into g
select (g.Key)
}
query {
for d in context.table do
groupBy (new {d.col1, d.col2}) into g
select (g.Key)
}
new {d.col1, d.col2}
C#の無名型を構築します。これは有効なF#ではありません。 - Jay
g.Count()
代わりに、何が起こるか見てください。 3.0を試していません...推測しているだけです。 - Danielg.Key
パラメータなしのコンストラクタを持たないタプルです。select 1
私の推測が正しければ、しかし、動作するはずです。 - Danielselect g.Key
ではない構築または初期化しかし、新しいタプルです。気が付く、select (g.Key)
になりますTuple<Tuple<col1_t, col2_t>>
これはのコンストラクタを呼び出していますTuple<'T1>
;select g.Key
になりますTuple<col1_t, col2_t>
新しい値を初期化するのではなく、既存の値を再利用します。もちろん、私は例外が原因で発生しているという前提で実行していますselect
ではなくgroupBy
これはまったく間違っている可能性があります。 :-P - ildjarn