2012-01-24 10 views
8

Me gustaría agrupar mi consulta LINQ por ItemNumber y devolver toda la tabla con el total de Quantity.Grupo de expresiones Lambda en C#

Example: 
ItemNumber - ItemName - Quantity 
100   Item1  1 
150   Item2  2 
100   Item1  2 
200   Item3  1 
150   Item2  2 

Should be: 
ItemNumber - ItemName - Quantity 
100   Item1  3 
150   Item2  4 
200   Item3  1 

Esta es la consulta que estoy tratando de grupo:

public IQueryable<WebsiteOrderStatus> GetOrderStatusByAccountNumberWithoutDeleted 
     (string accountNumber) 
{ 
    return db.WebsiteOrderStatus 
      .Where(x => x.AccountNumber == accountNumber && x.LastUpdatedStatus != 1); 
} 

Y mi mejor resultado hasta el momento (esto no se puede compilar sin embargo):

public IQueryable<IGrouping<Int32?, WebsiteOrderStatus>> lol(string accountNumber) 
{ 
    db.WebsiteOrderStatus 
     .Where(x => x.AccountNumber == accountNumber && x.LastUpdatedStatus != 1) 
     .GroupBy(g => g.ItemNumber) 
     .Select(g => new 
        { 
         g.Key.ItemNumber, 
         Column1 = (Int32?)g.Sum(p => p.Quantity) 
        }); 
} 

EDIT:

Gracias por las respuestas de todos, debo enfrentarlo. En mi opinión, estos tipos anónimos son bastante difíciles de trabajar, así que encontré otra solución.

Hice otro método, que suma la cantidad de elementos de los usuarios y agrupó el primero.

public IQueryable<WebsiteOrderStatus> GetOrderStatusByAccountNumberWithoutDeleted(string accountNumber) 
{ 
    return db.WebsiteOrderStatus.Where(x => x.AccountNumber == accountNumber && x.LastUpdatedStatus != 1).GroupBy(x => x.ItemNumber).Select(grp => grp.First()); 
} 

public int GetQuantityOfUsersItem(string accountNumber, string itemNumber) 
{ 
    return db.WebsiteOrderStatus.Where(x => x.ItemNumber == itemNumber && x.AccountNumber == accountNumber).Sum(x => x.Quantity); 
} 

En la página donde tengo mi gridview que hice:

var query = websiteOrderStatusRep.GetOrderStatusByAccountNumberWithoutDeleted(AppSession.CurrentLoginTicket.AccountNumber).Select(x => new { x.ItemName, x.ItemNumber, x.FormatName, x.Price, x.Status, x.Levering, Quantity = websiteOrderStatusRep.GetQuantityOfUsersItem(x.AccountNumber, x.ItemNumber)}); 
+1

No está seguro de qué otra cosa está mal, pero al menos, usted' falta un "retorno" en la segunda muestra. – Ani

+0

¿Cuál es el error de compilación que está obteniendo? –

+1

Probablemente está tratando de tratar a g.Key como un objeto, mientras que es solo el int. Si quiere el nombre del elemento en el resultado, entonces también tendrá que almacenarlo en el objeto clave (y convertir las teclas en un objeto que sea comparable) o leerlo de la primera entrada en el enumberator del grupo, supongo. – Rup

Respuesta

10
public IQueryable<IGrouping<Int32?, WebsiteOrderStatus>> lol(string accountNumber) 
{ 
    db.WebsiteOrderStatus 
     .Where(x => x.AccountNumber == accountNumber && x.LastUpdatedStatus != 1) 
     .GroupBy(g => g.ItemNumber) 
     .Select(g => new 
        { 
         ItemNumber = g.Key, 
         ItemName = g.First().ItemName, 
         Count = g.Sum(item => item.Quantity) 
        }); 
} 
3

creo que el Select debería ser:

.Select(g => new 
       { 
        ItemNumber = g.Key, 
        Column1 = (Int32?)g.Sum(p => p.Quantity) 
       }); 

nota el cambio en la primera línea de el tipo anónimo La clave de la agrupación ya es el número de artículo.

5

Los únicos problemas que veo con la consulta se

  1. Missing return declaración según comentarios
  2. La instrucción de selección debería ser:

-

.Select(g => new { 
     ItemNumber = g.Key, 
     Total = g.Sum(p => p.Quantity) 
    }); 

EDIT: Si desea obtener, digamos ItemNumber y NombreDeElemento, en el objeto resultante, también debe grupo en esos campos

db.WebsiteOrderStatus 
    .Where(x => x.AccountNumber == accountNumber && x.LastUpdatedStatus != 1) 
    .GroupBy(g => new { g.ItemNumber, g.ItemName }) 
    .Select(g => new 
       { 
        ItemNumber = g.Key.ItemNumber, 
        ItemName = g.Key.ItemName, 
        Count = g.Sum(item => item.Quantity) 
       }); 
+0

Parece que solo devuelve ItemNumber y Total a continuación. Lo que quiero es la tabla completa solo con una columna llamada total, que contiene el total de la cantidad – KLIM8D

+0

@ KLIM8D - Ver la actualización – Jamiec

+0

, así que cada objeto que quiero obtener en el resultado debe estar en la agrupación. De hecho, tengo 5 otros campos en la tabla, ¿podría haber una mejor manera de hacer esta agrupación que no sean todos los campos que necesito que estén contenidos en el grupo? – KLIM8D

7
public IQueryable<OrderStatus > lol(string accountNumber) 
{ 
    return db.WebsiteOrderStatus 
     .Where(x => x.AccountNumber == accountNumber && x.LastUpdatedStatus != 1) 
     .GroupBy(g => g.ItemNumber) 
     .Select(g => 
       new OrderStatus //This is your custom class, for binding only 
       { 
        ItemNumber = g.Key, 
        ItemName = g.First().ItemName, 
        Quantity = g.Sum(g => g.Quantity) 
       } 
     ); 
} 
+0

Estamos casi allí, sin errores hasta que estoy tratando de unir mi consulta a una vista de cuadrícula Recibo esta excepción: System.NotSupportedException: no se permite la construcción explícita del tipo de entidad 'GWportal.BusinessLayer.Repository.WebsiteOrderStatus' en la consulta. – KLIM8D

+2

'Las entidades pueden crearse fuera de las consultas e insertarse en el almacén de datos utilizando un DataContext. A continuación, puede recuperarlos mediante consultas. Sin embargo, no puede crear entidades como parte de una consulta. En este caso, deberá crear una clase personalizada para el enlace y asignar 'WebsiteOrderStatus' al objeto de esa clase. –

2

No puede utilizar tipo anónimo para el tipo de valor de retorno. Entonces nunca compilarás el código.

También su expresión linq tiene IQueryable < [tipo anónimo]> tipo de resultado.

yo creo que se puede hacer algo como esto:

public IQueryable<OrderStatus> lol(string accountNumber) 
{ 
    db.WebsiteOrderStatus 
     .Where(order => order.AccountNumber == accountNumber && order.LastUpdatedStatus != 1) 
     .GroupBy(order => order.ItemNumber) 
     .Select(grouping => new OrderStatus //This is your custom class, for binding only 
        { 
         ItemNumber = grouping.Key, 
         ItemName = grouping.First().ItemName, 
         Quantity = grouping.Sum(order => order.Quantity) 
        }); 
} 

`he fijado mi respuesta también :)

+0

¿Por qué no puede usar tipos anónimos como valor de retorno? – Jamiec

+1

¿Cómo se especifica en la firma del método? –

+0

MSDN: No puede declarar un campo, una propiedad, un evento o el tipo de devolución de un método como de tipo anónimo. Del mismo modo, no puede declarar que un parámetro formal de un método, propiedad, constructor o indizador tiene un tipo anónimo. Para pasar un tipo anónimo, o una colección que contiene tipos anónimos, como un argumento para un método, puede declarar el parámetro como tipo de objeto. Sin embargo, al hacerlo, se frustra el propósito de una tipificación fuerte. Si debe almacenar los resultados de la consulta o pasarlos fuera del límite del método, considere el uso de una estructura o clase denominada ordinaria en lugar de un tipo anónimo. –