f# f#-3.0

agrupado por columnas mĂșltiples en una consulta F#3.0



f#-3.0 (7)

Simplemente probando F # 3.0 y golpear un poco de una pared cuando se trata de agrupar por múltiples columnas. Lo obvio para intentar era

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

Pero obtengo un "Solo los constructores y los inicializadores sin parámetros son compatibles con LINQ to Entities". excepción.

Parece que no puedo encontrar un ejemplo en 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

Y me doy cuenta de que mi pregunta es similar a " Entity Framework and Anonymous Types in F # ", pero parece ser powerpack / F # 2.x centrado y espero que F # 3.0 tenga una respuesta elegante ... ¿Alguna idea?

ACTUALIZAR:

Me encontré con el atributo CLIMutable al leer la publicación de Brian en:

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

Yo era bastante optimista, así que lo intenté

[<CLIMutable>] type MyRecord = { Column1 : int; Column2 : int } query { for d in context.table do groupBy {Column1 = col1; Column2 = col2} into g select (g.Key) }

Desafortunadamente recibo la misma excepción exacta.


Al usar groupBy, necesita seleccionar una función de agregación (por ejemplo, count, sum, avg ...).


Primero debe recordar que una consulta se traduce en SQL real en algún momento. Parece que linq no admite el uso de varias claves de grupo como Tuple<> . Por lo tanto, cualquier transformación en Tuple<> debe realizarse después de que se haya completado la llamada a la base de datos.

En segundo lugar, debe poder lograr múltiples agrupaciones de teclas realizando múltiples agrupaciones detrás de las otras en las claves respectivas:

query { for d1 in context.table do groupBy d1.col1 into g1 for d2 in g1 do groupBy d2.col2 into g2 select g2 }

Por favor, ten piedad de mí si la sintaxis no es 100% ya que F # no es mi lengua materna :) Sin embargo, el concepto debería funcionar bien.


query { for d in context.table do groupBy (new {d.col1, d.col2}) into g select (g.Key) }


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()) }


Veo esto en el primero de sus enlaces, creo que es lo que quiere:

query { for student in db.Student do groupValBy student.Name student.Age into g select (g, g.Key, g.Count()) }


El siguiente es un ejemplo de columnas múltiples que se usan para agrupar en c # y convertir a f # (la administración excesivamente paranoica me ha hecho cambiar el nombre de todo, pero creo que he sido coherente):

(TheDatabase fue generado por SqlMetal, GetSummedValuesResult es un tipo de registro F #)

do#

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>

Entonces, lo que hay que usar es Microsoft.FSharp.Linq.RuntimeHelpers.AnonymousObject

Tenga en cuenta que no debe usar el módulo Seq para las funciones de agregación.

SummedValues = grouping |> Seq.sumBy (fun g -> g.SomeValues)

Aunque esto FUNCIONARÁ, hace la agregación en el lado del cliente, en lugar de formular el SQL apropiado.


//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) }