2008-12-21 39 views
5

estoy utilizando LINQ a EF y tienen el siguiente LINQ consulta:mediante LINQ ¿Cómo puedo tener una agrupación por un "campo calculado"

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

Así que este tipo de me lleva a donde quiero estar, en eso obtengo los artículos desglosados ​​por año y un recuento de artículos en ese año. (es decir, 2001 - 10, 1975 - 15, 2005 - 5, 1976 - 1) Lo que realmente quiero hacer es desglosarlos por década (es decir, 2000s - 15, 1970s - 16).

¿Cómo se tiene un "campo calculado" en la parte "por" de la cláusula de grupo para una instrucción Linq. Creo que lo que quiero es básicamente algo como:

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

o más generalmente la sintaxis para que pueda hacer algo más complicado de evaluación/cálculo para hacer el grupo por sobre. ¿Algunas ideas?

EDITAR (actualización):

(. X => x.Year.Value.ToString() Subcadena (0, 3) + "0s") - no funciona - "LINQ a Entidades no lo hace reconocer el método 'System.String ToString()' método, y este método no se puede traducir a una expresión de tienda. "

(x.Year/10 * 10) - Funcionalmente obras (gracias) - el único "problema" es que la 's' no está en el extremo (es decir, 1970 vs. 1970)

¿Hay de todos modos para poner una función en la cláusula by? es decir, agrupar x por este. ManipularAño (x.Año) en décadas ... o ... x => x.Año.Valor.ToString(). Subcadena (0,3) + "0s" ?? Sería bueno tener alguna técnica (como llamar a una función o usar una expresión lambda) para poder cubrir cualquier caso que se me ocurra.

Gracias de nuevo por la ayuda de todos en esto.

Respuesta

2

Parece que no podemos hacer una agrupación o seleccionar o similar sobre los campos calculados que se definied en las clases parciales en la entidad marco de referencia.

Los campos calculados se puede utilizar en LINQ a objetos (por lo que podría devolver todos los datos como objetos y luego hacer una agrupación)

0

Creo que encadenaría el método SelectMany al final de su resultado. Esto devuelve un IEnumerable de IEnumerables.

+1

No, una agrupación que ya es un IEnumerable de IEnumerables (como IGrouping extiende IEnumberable). No hay necesidad de SelectMany aquí. –

6

¿Qué tal agrupar por x.Year/10? (No he probado esto!)

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: Se ha cambiado (x.Year/10) a (x.Year/10 * 10) para obtener, por ejemplo, 1980 en lugar de 198.

EDIT2: en su ejemplo, "group x by x.Year.Value.ToString(). Substring (0, 3) +" 0s "en décadas" debería funcionar también. Sin necesidad de la sintaxis de lamba.

EDIT3: Se ha quitado un extra * 10. ¡Gracias Marc!

+0

En LINQ-to-Objects que debería estar bien. Con EF, necesitaría verificar dos veces cómo se calcula la aritmética (int/float/etc). Es posible que desee 'Matemáticas.Floor (x.Year/10) * 10', por ejemplo, suponiendo que EF puede asignar 'Math.Floor' al' PISO' de TSQL. –

+0

Oh, podría tener * 10 dos veces (una vez en el 'grupo', una vez en' seleccionar nuevo') –

+0

.ToString() no funciona (no se puede asignar a un error de tipo SQL) - no lo he hecho probado la solución "matemática", pero parece que podría resolver este caso. Me gustaría saber cómo hacerlo para todos los casos (es decir, los que no tienen una solución de tipo matemático o los que necesitan una serie de sentencias if o similares). – ChrisHDog

7

Usted puede utilizar la cláusula let para evitar contar las décadas varias veces:

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

Buen punto. Probablemente no hará una diferencia en LINQ to SQL, pero definitivamente le ahorrará un recuento adicional() en LINQ to Objects. – Lucas

Cuestiones relacionadas