Почему это выражение linq не работает? - PullRequest
5 голосов
/ 28 января 2010

Я использую LINQ to Entities.

У меня есть стол под названием Студент; он имеет идентификатор и имя в качестве столбцов. Идентификатор является первичным ключом.

Я бы хотел иметь возможность выбрать имя ученика и получить количество учеников с тем же именем.

Так, например, я бы использовал это в качестве данных моей таблицы.

ID  Name  
1   Bob
2   Will
3   Bob

После выполнения запроса я вернул бы список объектов Student, выглядящих следующим образом.

Name    Quantity
Bob     2
Will    1

Полагаю, это похоже на страницу тегов в stackoverflow; У него есть название и количество.

В любом случае, я создал частичный класс с именем Student.cs, в который я добавил следующее свойство:

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

Я придумал это, но я получаю ошибку ..

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

Ошибка, которую я получаю, говорит что-то вроде Не могу преобразовать из типа Anonymous в список Student. Это как-то связано с тем, что не распознается поле количества, которое я добавил в частичный класс?

Спасибо!

Ответы [ 7 ]

4 голосов
/ 28 января 2010

Измените тип Student, чтобы он выглядел следующим образом:

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

И ваш запрос будет выглядеть так:

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

Ваш метод возвращает IQueryable<Student>, но в настоящее время вы возвращаете IQueryable<T> прогнозируемого анонимного типа.

Вам необходимо провести рефакторинг вашего типа Student, чтобы иметь свойство Name типа String, а затем спроецировать новые экземпляры вашего типа Student из выражения, чтобы тип возврата вашего выражения совпадал с возвращаемым тип вашего метода.

2 голосов
/ 28 января 2010

Возвращаемое значение метода связывает коллекцию "students" с IQueryable<Student>, но ... выражение Linq создает IQueryable<some anonymous type>, и между ними нет преобразования.

Вы можете сделать шаг дальше, изменив выбранную вами часть на:

select new Student() {....}

Надеюсь, это поможет,

Tyler

2 голосов
/ 28 января 2010

Ваша функция возвращает ученика

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

Но ваш запрос Linq возвращает новый тип, который содержит Name и Int (count)

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

y-попробуйте выбрать нового ученика

2 голосов
/ 28 января 2010

Ключевые слова select new вызывают изменение формы данных, что означает, что запрос LINQ не будет возвращать IQueryable , а скорее анонимный тип, содержащий свойства «Имя» и «Количество». Если вы измените его так, чтобы он возвращал конкретный тип, а не анонимный, вы сможете получать данные в нужной форме.

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;
}
2 голосов
/ 28 января 2010

Проблема в том, что вы не возвращаете студентов - вы пытаетесь вернуть анонимный тип из вашей функции. Это не разрешено.

Создайте класс для представления вашего результата и используйте new MyClass { ... } вместо new { ... } в запросе и измените метод так, чтобы он возвращал IQueryable<MyClass> вместо IQueryable<Student>.

Например, вы можете создать класс с именем StudentNameAndResults.

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

Кроме того, вы можете просто вернуть результат в виде словаря или IEnumarable из IGrouping. Например:

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

Кроме того, созданное вами свойство использует подробный синтаксис из дней до C # 3.0. Теперь вы можете использовать автоматически реализованные свойства , если вам не нужна особая логика:

public int Quantity { get; set; }
1 голос
/ 28 января 2010

Вы выполняете проекцию в своем запросе linq. Если вы наведите курсор на var students внутри vs, вы увидите коллекцию анонимного типа.

Если вы хотите вернуть IQueryabley<Student>, вам нужно сделать:

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

Внешние методы не могут знать об анонимном типе, который вы создали в предыдущем примере, поэтому вы не сможете вернуть типизированную коллекцию.

Используя предложенный мною метод, вы все равно сможете в дальнейшем проецировать возвращаемое значение вашего метода, поскольку IQueryable компонуется до первого перечисления:

var students = FindStudentsDistinctWithQuantity();
var namesAndQunatity = from s in students select new {s.Name, s.Quantity};
1 голос
/ 28 января 2010
 var students= (from s in db.Students
                    group s by s.Name into g
                    select new {Name = g.Key, Quantity = g.Count()}); 

Это анонимный тип, а не IQueryable<Student>. Либо вам нужно вернуть System.Object, либо вам нужно вернуть IQueryable<Student> следующим образом ...

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

Где Student определяет свойства, используемые при инициализации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...