为什么这个linq表达式不起作用?

时间:2010-01-28 19:51:37

标签: c# asp.net linq linq-to-entities

我正在使用LINQ to Entities。

我有一张叫做学生的桌子;它有ID和Name作为列。 ID是主键。

我希望能够选择学生的姓名,并获得具有相同姓名的学生数量。

例如,我将此作为我的表数据。

ID  Name  
1   Bob
2   Will
3   Bob

执行查询后,我将返回一个看起来像这样的学生对象列表。

Name    Quantity
Bob     2
Will    1

我猜它有点类似于stackoverflow的Tags页面的工作方式;它有名称和数量。

无论如何,我创建了一个名为Student.cs的分部类,其中我添加了一个Quantity属性。

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

我得到的错误说的是无法从匿名类型转换为学生列表。它是否与它有关而没有识别我在分部类中添加的数量字段?

谢谢!

7 个答案:

答案 0 :(得分:4)

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的{​​{1}}属性,然后从表达式中投射String类型的新实例,以便返回表达式的类型将与方法的返回类型匹配。

答案 1 :(得分:2)

问题是你没有回来的学生 - 你试图从你的功能中返回一个匿名类型。这是不允许的。

创建一个类来表示您的结果,并在查询中使用new MyClass { ... }而不是new { ... },并将方法更改为返回IQueryable<MyClass>而不是IQueryable<Student>

例如,您可以创建一个名为StudentNameAndResults的类。

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

或者,您可以将结果作为字典或IGrouping的IEnumarable返回。例如:

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天的详细语法。现在,如果您不需要任何特殊逻辑,则可以使用auto-implemented properties

public int Quantity { get; set; }

答案 2 :(得分:2)

select new关键字导致数据的形式发生变化,这意味着LINQ查询不会返回IQueryable&lt; Student&gt;,而是返回包含“Name”和“Quantity”属性的匿名类型。如果您更改它以返回具体类型而不是匿名类型,您将能够以所需的形式检索数据。

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

答案 3 :(得分:2)

您的函数返回学生

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

但是你的Linq查询返回一个包含Name和Int(count)

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

y-try选择新学生{Name = g.Key,Quantity = g.Count()}

答案 4 :(得分:2)

该方法的返回值将“students”集合与IQueryable<Student>绑定,但是...... Linq表达式正在创建IQueryable<some anonymous type>,并且两者之间没有转换。

通过修改您选择的部分,您可以进一步了解宝贝:

select new Student() {....}

希望这会有所帮助,

泰勒

答案 5 :(得分:1)

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

学生定义初始化中使用的属性。

答案 6 :(得分:1)

您正在linq查询中进行投影。如果你将光标悬停在var students内部,你会看到它是一个匿名类型的集合。

如果您想要返回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};