2008-09-30 16 views
6

¿Cómo crearía la consulta de Linq To Objects equivalente?consulta LINQ con múltiples agregados

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 

Respuesta

2

No puede seleccionar de forma eficiente múltiples agregados en vainilla LINQ a Objetos. Puede realizar múltiples consultas, por supuesto, pero eso puede ser ineficiente dependiendo de su fuente de datos.

Tengo un marco que hace frente a esto que llamo "Push LINQ" - es solo un hobby (para mí y Marc Gravell) pero creemos que funciona bastante bien. Está disponible como parte de MiscUtil, y puede leer sobre esto en my blog post on it.

Parece un tanto extraño, porque usted define dónde quiere que los resultados vayan como "futuros", luego inserta los datos a través de la consulta y luego recupera los resultados, pero una vez que lo entiende, está bien. Me interesaría saber cómo te va con eso; si lo usas, mándame un correo a [email protected]

+0

Gracias Jon. Una de las partes más difíciles de Linq hasta ahora es descubrir qué puedes y qué no puedes hacer. Definitivamente echaré un vistazo a tu técnica de Push una vez que me sienta un poco más cómodo con la metodología estándar. –

4

Enumeración única que produce tanto el mínimo como el máximo (y cualquier otro agregado que desee agregar allí). Esto es mucho más fácil en vb.net.

Sé que esto no maneja la caja vacía. Eso es bastante fácil de agregar.

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

Es un poco manual pero es lo suficientemente bueno para mí. Es curioso cómo cuando rompes el límite, rápidamente vuelves a los atajos sintácticos para una apariencia foreach. –

+0

Irónico, ¿no es así? foreach es solo un atajo sintáctico. –

+0

Downvoter, ¿me gustaría comentar? –

0

Es posible hacer múltiples agregados con LINQ a objetos, pero es un poco feo.

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?)) 
    } 
); 

También habría que las funciones mínimas y máximas para DateTime ya que estos no son estándar disponible.

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; 
} 
Cuestiones relacionadas