none
Entity Framework Abfrage RRS feed

  • Frage

  • Hallo Experten,

    grüble jetzt schon ein paar Stunden wie ich das in einer Abfrage lösen könnte. Folgende Abfrage bringt mir die Anzahl der Beratungen pro Monat (Anzahl der Beratungen = Anzahl der Buchungen).

                var anzahlberatungenmonat = context.Buchungs
                    .Where(b => b.AbteilungID == _login.Abteilungsnummer && b.Von >= vondatum && b.Bis <= bisdatum)
                    .GroupBy(b => new { Monat = b.Von.Month })
                    .Select(b => new { Monat = b.Key.Monat, Anzahl = b.Count() })
                    .ToList();
    

    Jetzt bräuchte ich eine Erweiterung die mir nur das erste Auftreten einer Person zählt (KlientID). Und zwar im ersten Monat, also wenn jemand im Jänner und im März eine Beratung hatte, dann soll der Klient nur im Jänner gezählt werden. Geht das überhaupt oder muss ich das mit einer Schleife nachher machen.

    Viele Grüße

    Siegfried


    Samstag, 18. April 2015 17:49

Antworten

  • Hallo Siegfried,

    wenn ich dich richtig verstehe sollte es mit folgender Abfrage funktionieren:

    var anzahlberatungenmonat = Buchungs
        .Where(b => b.AbteilungID == _login.Abteilungsnummer && b.Von >= vondatum && b.Bis <= bisdatum)
        .GroupBy(x => x.KlientID)
        .Select(x => x.OrderBy(y => y.Von).First())
        .GroupBy(b => new { Monat = b.Von.Month })
        .Select(b => new { Monat = b.Key.Monat, Anzahl = b.Count() })
        .ToList();

    Es wird zunächst nach KlientID gruppiert und dann wird aus jeder Liste der Kunde heraus gesucht der den kleinsten Wert für Von hat. Der nächste GroupBy Aufruf bekommt dann wieder eine Liste von Buchung-Objekten.

    Die Buchungen der nachfolgenden Monate, die unter der selben KlientID eingetragen sind, werden ignoriert. Innerhalb des ersten Monats wird nach meinem Code auch nur der aller erste Eintrag gezählt. Wenn du möchtest, dass trotzdem alle Einträge des ersten Monats gezählt werden, musst du den Select-Aufruf noch etwas anpassen:

    .SelectMany(x =>
    {
        var n = x.OrderBy(y => y.Von).First();
        return x.Where(y => y.Von.Year == n.Von.Year && y.Von.Month == n.Von.Month);
    })

    Da hier nun eine ganze Unterliste entstehen kann, muss diese mit SelectMany wieder komplett in die oberste Ebene übertragen werden. Der Rest bleibt gleich.

    PS: Auch wenn du es nicht direkt siehst, auch hier gibt es Schleifen. Nur verstecken sie sich hinter den Methoden und arbeiten zusammen mehr so als wäre es eine große Schleife.


    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    Sonntag, 19. April 2015 02:23
    Moderator

Alle Antworten

  • Hallo Siegfried,

    wenn ich dich richtig verstehe sollte es mit folgender Abfrage funktionieren:

    var anzahlberatungenmonat = Buchungs
        .Where(b => b.AbteilungID == _login.Abteilungsnummer && b.Von >= vondatum && b.Bis <= bisdatum)
        .GroupBy(x => x.KlientID)
        .Select(x => x.OrderBy(y => y.Von).First())
        .GroupBy(b => new { Monat = b.Von.Month })
        .Select(b => new { Monat = b.Key.Monat, Anzahl = b.Count() })
        .ToList();

    Es wird zunächst nach KlientID gruppiert und dann wird aus jeder Liste der Kunde heraus gesucht der den kleinsten Wert für Von hat. Der nächste GroupBy Aufruf bekommt dann wieder eine Liste von Buchung-Objekten.

    Die Buchungen der nachfolgenden Monate, die unter der selben KlientID eingetragen sind, werden ignoriert. Innerhalb des ersten Monats wird nach meinem Code auch nur der aller erste Eintrag gezählt. Wenn du möchtest, dass trotzdem alle Einträge des ersten Monats gezählt werden, musst du den Select-Aufruf noch etwas anpassen:

    .SelectMany(x =>
    {
        var n = x.OrderBy(y => y.Von).First();
        return x.Where(y => y.Von.Year == n.Von.Year && y.Von.Month == n.Von.Month);
    })

    Da hier nun eine ganze Unterliste entstehen kann, muss diese mit SelectMany wieder komplett in die oberste Ebene übertragen werden. Der Rest bleibt gleich.

    PS: Auch wenn du es nicht direkt siehst, auch hier gibt es Schleifen. Nur verstecken sie sich hinter den Methoden und arbeiten zusammen mehr so als wäre es eine große Schleife.


    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    Sonntag, 19. April 2015 02:23
    Moderator
  • Hallo Tom,

    genial, ich musste nur eine kleine Amnpassung machen weil ich folgende Exception bekommen habe.

    An unhandled exception of type 'System.NotSupportedException' occurred in EntityFramework.SqlServer.dll

    Additional information: The method 'First' can only be used as a final query operation. Consider using the method 'FirstOrDefault' in this instance instead.

                var anzahlklientenmonat = context.Buchungs
                    .Where(b => b.AbteilungID == _login.Abteilungsnummer && b.Von >= vondatum && b.Bis <= bisdatum)
                    .GroupBy(x => x.KlientID)
                    .Select(x => x.OrderBy(y => y.Von).FirstOrDefault())
                    .GroupBy(b => new { Monat = b.Von.Month })
                    .Select(b => new { Monat = b.Key.Monat, Anzahl = b.Count() })
                    .ToList();
                
    

    Habe es schon kontrolliert, das Ergebnis stimmt.

    Danke für Deine Hilfe,

    Siegfried

    Sonntag, 19. April 2015 07:59