2008-09-30 7 views
6

Comment créer la requête Linq To Objects équivalente?Requête LINQ avec plusieurs agrégats

SELECT MIN(CASE WHEN p.type = "In" THEN p.PunchTime ELSE NULL END) AS EarliestIn, 
     MAX(CASE WHEN p.type = "Out" THEN p.PunchTime ELSE NULL END) AS LatestOUt 
FROM Punches p 

Répondre

2

Vous ne pouvez pas sélectionner efficacement plusieurs agrégats dans LINQ aux objets vanille. Bien sûr, vous pouvez effectuer plusieurs requêtes, mais cela peut s'avérer inefficace en fonction de votre source de données.

J'ai un framework qui fait face à ce que j'appelle "Push LINQ" - ce n'est qu'un hobby (pour moi et Marc Gravell) mais nous pensons que ça marche plutôt bien. Il est disponible dans le cadre de MiscUtil, et vous pouvez lire à ce sujet dans my blog post on it. Il semble quelque peu étrange - parce que vous définissez où vous voulez que les résultats se passent comme «futurs», puis pousser les données à travers la requête, puis récupérer les résultats - mais une fois que vous obtenez votre tête autour, c'est bien. Je serais intéressé de savoir comment vous y prenez. Si vous l'utilisez, envoyez-moi un mail à [email protected]

+0

Merci Jon. L'une des parties les plus difficiles à propos de Linq jusqu'ici est de déterminer ce que vous pouvez et ne pouvez pas faire. Je vais certainement jeter un coup d'oeil à votre technique de Push une fois que je serai un peu plus à l'aise avec la méthodologie standard. –

4

Énumération simple produisant à la fois min et max (et tout autre agrégat que vous voulez y jeter). C'est beaucoup plus facile sur vb.net.

Je sais que cela ne gère pas le cas vide. C'est assez facile à ajouter.

List<int> myInts = new List<int>() { 1, 4, 2, 0, 3 }; 
    var y = myInts.Aggregate(
     new { Min = int.MaxValue, Max = int.MinValue }, 
     (a, i) => 
     new 
     { 
      Min = (i < a.Min) ? i : a.Min, 
      Max = (a.Max < i) ? i : a.Max 
     }); 
    Console.WriteLine("{0} {1}", y.Min, y.Max); 
+0

C'est un peu manuel mais c'est assez bon pour moi. Il est amusant de constater que lorsque vous cassez linq, vous revenez rapidement à des raccourcis syntaxiques pour un look foreach. –

+0

Ironique alors, n'est-ce pas? foreach est juste un raccourci syntaxique. –

+0

Downvoter, vous voulez commenter? –

0

Il est possible de faire plusieurs agrégats avec LINQ-to-Objects, mais c'est un peu moche.

var times = punches.Aggregate(
    new { EarliestIn = default(DateTime?), LatestOut = default(DateTime?) }, 
    (agg, p) => new { 
     EarliestIn = Min(
      agg.EarliestIn, 
      p.type == "In" ? (DateTime?)p.PunchTime : default(DateTime?)), 
     LatestOut = Max(
      agg.LatestOut, 
      p.type == "Out" ? (DateTime?)p.PunchTime : default(DateTime?)) 
    } 
); 

Vous auriez également besoin des fonctions Min et Max pour DateTime car elles ne sont pas disponibles en standard.

public static DateTime? Max(DateTime? d1, DateTime? d2) 
{ 
    if (!d1.HasValue) 
     return d2; 
    if (!d2.HasValue) 
     return d1; 
    return d1.Value > d2.Value ? d1 : d2; 
} 
public static DateTime? Min(DateTime? d1, DateTime? d2) 
{ 
    if (!d1.HasValue) 
     return d2; 
    if (!d2.HasValue) 
     return d1; 
    return d1.Value < d2.Value ? d1 : d2; 
}