2008-12-21 2 views
5

ich LINQ to EF verwende und die folgende LINQ-Abfrage haben:Mit LINQ, wie habe ich eine Gruppierung durch ein „berechnetes Feld“

var results = (from x in ctx.Items 
       group x by x.Year into decades 
       orderby decades.Count() descending 
       select new { Decade = decades.Key, DecadeCount = decades.Count() }); 

Also diese Art von bekommt mir, wo ich sein möchte, indem ich die Items nach Jahr und Anzahl der Items in diesem Jahr aufschlüsselt. (d. h. 2001 - 10, 1975 - 15, 2005 - 5, 1976 - 1) Das, was ich wirklich tun möchte, ist es, sie nach zehn Jahren aufzubrechen (d. h. 2000 - 15, 1970 - 16).

Wie hat man ein "berechnetes Feld" im "by" -Teil der Gruppenklausel für eine Linq-Anweisung. Ich denke, was ich will, ist im Grunde so etwas wie:

var results = (from x in ctx.Items 
       group x by (x => x.Year.Value.ToString().Substring(0, 3) + "0s") into decades 
       orderby decades.Count() descending 
       select new { Decade = decades.Key, DecadeCount = decades.Count() }); 

Oder allgemeiner die Syntax, so dass ich komplizierte Auswertung/Berechnung etwas mehr tun, um die Gruppe, indem Sie auf tun. Irgendwelche Ideen?

EDIT (Update):

(. X => x.Year.Value.ToString() Substring (0, 3) + "0") - funktioniert nicht - „LINQ to Entities nicht Erkennen Sie die Methode 'System.String ToString()', und diese Methode kann nicht in einen Speicherausdruck übersetzt werden. "

(x.Year/10 * 10) - Funktionell arbeitet (danke) - das einzige "Problem" ist, dass die 's' nicht am Ende ist (dh 1970 vs. 1970)

Gibt es Wie auch immer, um eine Funktion in die By-Klausel zu setzen? d.h. Gruppe x durch this.ManipulateYear (x.Year) in Dekaden ... oder ... x => x.Year.Value.ToString(). Substring (0,3) + "0s" ?? Es wäre schön, eine Technik zu haben (zum Beispiel eine Funktion aufzurufen oder einen Lambda-Ausdruck zu verwenden), so dass ich jeden denkbaren Fall abdecken kann.

Nochmals vielen Dank für die Hilfe von allen.

Antwort

2

Es sieht aus wie wir nicht eine Gruppierung tun können, oder wählen oder ähnlich auf berechnete Felder, die in den Teilklassen auf der Einheit definiertem werden Rahmen.

Die berechneten Felder können auf LINQ zu Objekten verwendet werden (so können Sie alle Daten als Objekte zurück und führen Sie dann eine Gruppierung)

0

Ich glaube, Sie würden die SelectMany-Methode an das Ende Ihres Ergebnisses verketten. Dies gibt IEnumerable von IEnumerables zurück.

+1

Nein, eine Gruppierung ist bereits ein IEnumerable von IEnumerables (als IGrouping IEnumberable erstreckt). Keine Notwendigkeit für SelectMany hier. –

6

Wie wäre es mit der Gruppierung nach x.Year/10? (Habe nicht getestet!)

var results = (from x in ctx.Items 
       group x by (x.Year/10 * 10) into decades 
       orderby decades.Count() descending 
       select new { Decade = decades.Key, DecadeCount = decades.Count() }); 

EDIT1: Changed (x.Year/10) bis (x.Year/10 * 10) zu erhalten, zum Beispiel 1980 statt 198.

EDIT2: In Ihrem Beispiel sollte "group x by x.Year.Value.ToString(). Substring (0, 3) +" 0s ") in Dekaden" auch funktionieren. Keine Notwendigkeit für die Lamba-Syntax.

EDIT3: Ein extra * 10 entfernt. Danke Marc!

+0

In LINQ-to-Objects sollte das in Ordnung sein. Mit EF müssen Sie überprüfen, wie die Arithmetik berechnet wird (int/float/etc). Vielleicht möchtest du Math.Floor (x.Year/10) * 10' zum Beispiel - unter der Annahme, dass EF "Math.Floor" auf TSQLs "FLOOR" abbilden kann. –

+0

Oh, du hast vielleicht * 10 zweimal (einmal in der 'Gruppe', einmal im 'Select new') –

+0

die .ToString() funktioniert nicht (kann nicht zu SQL-Typ Fehler zuordnen) - ich habe nicht testete die "math" -Lösung, aber es scheint, als könnte es diesen Fall lösen. Ich würde gerne wissen, wie man es für alle Fälle macht (d. h. solche, die keine mathematische Lösung haben oder solche, die eine Reihe von if-Anweisungen oder ähnliches benötigen). – ChrisHDog

7

können Sie verwenden, um die let Klausel mehrere Male die Jahrzehnte zählen zu vermeiden:

from x in ctx.Items 
group x by (x.Year/10 * 10) into decades 
let decadeCount = decades.Count() 
orderby decadeCount descending 
select new { Decade = decades.Key, DecadeCount = decadeCount } 
+0

Guter Punkt. Es wird wahrscheinlich keinen Unterschied in LINQ zu SQL machen, aber wird Ihnen definitiv ein extra Count() in LINQ zu Objects speichern. – Lucas