2010-01-20 18 views
5

Soy nuevo en LINQ a SQL y me gustaría saber cómo lograr algo como esto en LINQ:grupo LINQ por la pregunta meses

 Month Hires Terminations 
     Jan  5  7 
     Feb  8  8 
     Marc  8  5 

Tengo esto hasta ahora, y creo que hay es algo malo con eso, pero no estoy seguro:

from term1 in HRSystemDB.Terminations 
group term1 by new { term1.TerminationDate.Month, term1.TerminationDate.Year } into grpTerm 
select new HiresVsTerminationsQuery 
{ 
    Date = Criteria.Period, 
    TerminationsCount = grpTerm.Count(term => term.TerminationDate.Month == Criteria.Period.Value.Month), 
    HiresCount = (from emp in HRSystemDB.Persons.OfType<Employee>() 
       group emp by new { emp.HireDate.Month, emp.HireDate.Year } into grpEmp 
       select grpEmp).Count(e => e.Key.Month == Criteria.Period.Value.Month) 
}); 

Gracias de antemano.

+0

Mostrar su esquema de base de datos ayudaría a eso. – Blindy

+0

¿Qué es 'Criteria.Period' y' Criteria.Period.Value.Month'? –

+0

¿Qué te hace sentir inseguro de que sea correcto? ¿Compila? ¿Has intentado ejecutarlo? ¿Da los resultados que esperas? –

Respuesta

6

No estoy muy seguro de dónde viene el valor Criteria.Period en su consulta de muestra.

Sin embargo, creo que está intentando leer las contrataciones y terminaciones de todos los meses disponibles (y luego puede filtrarlas fácilmente). Su consulta podría salir mal si la primera tabla (Terminación) no incluyó ningún registro para un mes específico (por ejemplo, mayo). Entonces, la cláusula select no se llamaría con "May" como parámetro e incluso si tenía algunos datos en la segunda tabla (que representa Hires), entonces no podría encontrarla.

Esto se puede resolver con elegancia usando el Concat method (vea ejemplos de MSDN). Se podría seleccionar todos termniations y todos los empleados (en una estructura de datos de algún tipo) y luego agrupar todos los datos por mes:

var terms = from t in HRSystemDB.Terminations 
      select new { Month = t.TerminationDate.Month, 
         Year = term1.TerminationDate.Year, 
         IsHire = false }; 
var hires = from emp in HRSystemDB.Persons.OfType<Employee>() 
      select new { Month = emp.HireDate.Month, 
         Year = emp.HireDate.Year 
         IsHire = true }; 

// Now we can merge the two inputs into one 
var summary = terms.Concat(hires); 

// And group the data using month or year 
var res = from s in summary 
      group s by new { s.Year, s.Month } into g 
      select new { Period = g.Key, 
         Hires = g.Count(info => info.IsHire), 
         Terminations = g.Count(info => !info.IsHire) } 

Al mirar el código de ahora, estoy bastante seguro de que es de alguna manera más corta para escribir esto Por otro lado, este código debe ser bastante legible, lo cual es un beneficio. También tenga en cuenta que no importa que dividamos el código en un par de subconsultas. Gracias a la evaluación lenta de LINQ to SQL, esto se debe ejecutar como una sola consulta.

+0

Esta es una muy buena respuesta de hecho. No sabía sobre el método concat. Voy a experimentar con él más tarde y publicar mis resultados. Gracias. – jasonco

+0

Has salvado mi vida. Funcionó muy bien! Justo lo que estaba buscando. ¡Gracias! +1 – jasonco

3

No sé si es más corto, pero también puede probar esta versión para ver si funciona mejor con su servidor. No sé exactamente cómo estas dos respuestas se convierten en declaraciones SQL. Uno podría estar mejor basado en sus índices y tal.

var terms = 
    from t in Terminations 
    group t by new {t.Month, t.Year} into g 
    select new {g.Key, Count = g.Count()}; 

var hires = 
    from p in Persons 
    group p by new {p.Month, p.Year} into g 
    select new {g.Key, Count = g.Count()}; 

var summary = 
    from t in terms 
    join h in hires on t.Key equals h.Key 
    select new {t.Key.Month, t.Key.Year, 
     Hires = h.Count, Terms = t.Count}; 
+0

Gracias por la respuesta. Esta versión funciona siempre que haya terminaciones o contrataciones en el mismo mes. Si no hubo contrataciones o despidos en ninguno de ellos, no se mostrarán resultados para ese mes en particular, incluso si hubo, digamos 2 contrataciones pero 0 terminaciones en mayo. Tuve que hacer una pequeña corrección, el grupo por (para mi caso particular) debería ser "grupo t por nuevo {t.TerminationDate.Month, t.TerminationDate.Year} en g" y "group p por nuevo {p. HireDate.Month, p.HireDate.Year} en g ". Aparte de eso, creo que es una buena respuesta. ¡Gracias! +1 :-) – jasonco