2010-01-28 21 views
5

Estoy usando LINQ to Entities.¿Por qué esta expresión linq no funciona?

Tengo una tabla llamada Estudiante; tiene ID y Nombre como sus columnas. ID es una clave principal.

Quisiera poder seleccionar el nombre del Estudiante y obtener la cantidad de Estudiantes con el mismo Nombre.

Así que, por ejemplo, tendría esto como datos de mi tabla.

ID Name 
1 Bob 
2 Will 
3 Bob 

Después de realizar la consulta, devolvería una lista de objetos estudiantiles con el siguiente aspecto.

Name Quantity 
Bob  2 
Will 1 

Supongo que es algo similar a cómo funciona la página Etiquetas de stackoverflow; Tiene el nombre y la cantidad.

De todos modos, creé una clase parcial llamada Student.cs en la que agregué una propiedad de Cantidad como esta.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 

namespace MySite.Models 
{ 
    public partial class Student 
    { 
     private int _quantity; 

     public int Quantity 
     { 
      get { return _quantity; } 
      set { _quantity = value; } 
     } 
    } 
} 

me ocurrió esto, pero yo estoy recibiendo un error ..

public IQueryable<Student> FindStudentsDistinctWithQuantity() 
    { 
     /*SELECT Name, COUNT(Name) AS Quantity 
     FROM Student 
     GROUP BY Name*/ 

     var students= (from s in db.Students 
        group s by s.Name into g 
        select new {Name = g.Key, Quantity = g.Count()});    

     return students; 
    } 

El error que estoy consiguiendo dice algo así como que no se puede convertir de tipo anónimo a la lista del Estudiante. ¿Tiene algo que ver con que no reconozca el campo de cantidad que agregué en la clase parcial?

Gracias!

+0

Algunos consejos generales: dejar de usar var hasta que obtenga más experiencia . Si hubiera intentado utilizar 'IQueryable = (a partir de ...', habría puesto a cero mucho más rápido en el problema. –

Respuesta

4

cambiar el tipo de Student a tener este aspecto:

public partial class Student 
{ 
    public Int32 Quantity { get; set; } 
    public String Name { get; set; } 
} 

Y su pregunta a este aspecto:

var students = from s in db.Students 
       group s by s.Name into g 
       select new Student { 
        Name = g.Key, 
        Quantity = g.Count() }; 

Su método devuelve IQueryable<Student> pero actualmente está devolviendo un IQueryable<T> de un tipo anónimo proyectado.

Usted deberás volver a tipo Student tener una propiedad de tipo NameString y luego proyectar nuevas instancias de su Student tipo de la expresión de modo que el tipo de retorno de expresión coincidirá con el tipo de retorno de su método.

+0

No se trata de "refactorizar" para corregir un error.Y el Estudiante como lo tiene definido anteriormente tiene un Nombre, porque es una clase parcial que se extiende desde su objeto Linq que tiene Nombre e ID. Ahora extender Estudiante para agregar una cantidad definitivamente es cuestionable, pero .... –

+0

¿Es una mala idea extender la clase Estudiante para agregar una propiedad de cantidad? No tengo una columna de cantidad en la base de datos para el alumno. Me gustaría devolver una lista de objetos Student para que en mi View (que hereda el objeto Student) pueda mostrar fácilmente la Cantidad. ¿Hay una manera diferente/mejor de hacerlo? – hanesjw

+0

Sí, esa es una mala idea: estaba mirando el código y no toda la imagen. –

2

El problema es que no estás devolviendo alumnos; estás tratando de devolver un tipo anónimo de tu función. Esto no esta permitido.

crear una clase para representar a su resultado y utilizar en lugar de new MyClass { ... }new { ... } en la consulta, y cambiar el método para devolver IQueryable<MyClass> en lugar de IQueryable<Student>.

Podría, por ejemplo, hacer una clase llamada StudentNameAndResults.

class StudentNameAndResults 
{ 
    public string Name { get; set; } 
    public int Quantity { get; set; } 
} 

Alternativamente, podría simplemente devolver el resultado como un diccionario o un IEnumarable de IGrouping. Por ejemplo:

public IDictionary<string, int> FindStudentsDistinctWithQuantity() 
{ 
    Database db = new Database(); 
    var students= (from s in db.Students 
       group s by s.Name into g 
       select new {Name = g.Key, Quantity = g.Count()}); 

    return students.ToDictionary(s => s.Name, s => s.Quantity); 
} 

Además, la propiedad que ha creado utiliza la sintaxis detallada de los días anteriores a C# 3.0. Ahora puede utilizar auto-implemented properties si usted no necesita ninguna lógica especial:

public int Quantity { get; set; } 
1
var students= (from s in db.Students 
        group s by s.Name into g 
        select new {Name = g.Key, Quantity = g.Count()}); 

Este es un tipo anónimo, no IQueryable<Student>. Ya sea que necesite devolver System.Object, o si tiene que volver IQueryable<Student> de la siguiente manera ...

return from s in db.Students 
     group s by s.Name into g 
     select new Student{Name = g.Key, Quantity = g.Count()}; 

donde el estudiante define las propiedades que se utilizan en el initializtion.

+0

Si bien puede devolver un tipo anónimo como System.Object, no ayuda mucho porque no puede usar los campos a menos que lo lance al subtipo correcto, y no sabe de qué tipo es. No recomendaría hacer esto. –

2

Los select new palabras clave están causando la forma de los datos a cambiar, lo que significa que la consulta LINQ no volverá IQueryable <Estudiante>, sino más bien un tipo anónimo que contiene el "Nombre" y propiedades "cantidad". Si lo cambia para devolver un tipo concreto en lugar de uno anónimo, podrá recuperar los datos en la forma que desee.

public class StudentGrouping { 
    public string Name { get; set; } 
    public int Quantity { get; set; } 
} 

public IQueryable<StudentGrouping> FindStudentsDistinctWithQuantity() 
{ 
    /*SELECT Name, COUNT(Name) AS Quantity 
    FROM Student 
    GROUP BY Name*/ 

    var students= (from s in db.Students 
       group s by s.Name into g 
       select new StudentGrouping { 
        Name = g.Key, 
        Quantity = g.Count() 
       }).AsQueryable();    

    return students; 
} 
+0

No estoy seguro de que AsQueryable() al final, ¿funcionará? –

2

Su función devuelve Estudiante

public IQueryable<Student> FindStudentsDistinctWithQuantity(){ ... } 

Pero la consulta LINQ devuelve un nuevo tipo que contiene un nombre y un Int (recuento)

   >>> select new {Name = g.Key, Quantity = g.Count()});    

y-tratar seleccione nuevo estudiante { Name = g.Key, Quantity = g.Count()}

1

Estás haciendo una proyección en tu consulta de linq. Si pasa el cursor sobre var students en el interior, verá que es una colección de tipo anónimo.

Si desea devolver un IQueryabley<Student> que tiene que hacer:

var students= from s in db.Students 
        group s by s.Name into g 
        select s.Key; 

No hay manera de métodos externos pueden saber sobre el tipo anónimo que ha creado en el ejemplo anterior, por lo que no podrá para devolver una colección mecanografiada

Con el método sugerí usted todavía será capaz de hacer una proyección sobre el valor de retorno del método más adelante, ya que IQueryable es componibles hasta que la primera enumeración:

var students = FindStudentsDistinctWithQuantity(); 
var namesAndQunatity = from s in students select new {s.Name, s.Quantity}; 
+0

Creo que el problema es que 'Student' no tiene' Quantity' en la base de datos y está tratando de agregarlo a la clase y configurarlo dentro de esta consulta. Entonces, si usaste tu sugerencia, yo diría que 'Quantity 'siempre se establecerá en 0. –

2

lazos valor de retorno del método de las "students" colección a IQueryable<Student> pero ... la expresión de Linq está creando un IQueryable<some anonymous type>, y no hay conversión entre los dos.

Usted puede obtener un bebé paso más allá mediante la modificación de su selecto parte para ser:

select new Student() {....} 

Esperemos que esto ayuda,

Tyler

Cuestiones relacionadas