C#LINQ .Contains返回空?

时间:2016-03-13 16:09:40

标签: c# linq contains

对于学校项目,我需要过滤在同一时间段注册多个课程的学生。我没有通过过程/视图查询数据库,而是想使用LINQ在内存中过滤它以用于学习目的。

根据调试器,一切似乎都没问题但是我的linq查询的结果是0,我无法弄清楚如何。

以下是代码:

foreach (Timeblock tb in ctx.Timeblocks)
        {
            List<Student> doublestudents = new List<Student>();

            //Get the schedules matching the timeblock.
            Schedule[] schedules = (from sched in ctx.Schedules
                                    where sched.Timeblock.Id == tb.Id
                                    select sched).ToArray();

            /\/\/\Gives me 2 schedules matching that timeblock.

            if (schedules.Count() > 1)
            {
                doublestudents = (from s in ctx.Students
                                  where s.Courses.Contains(schedules[0].Course) && s.Courses.Contains(schedules[1].Course)
                                  select s).ToList();

                Console.WriteLine(doublestudents.Count); <<< count results in 0 students.
            }

        }

调试时似乎一切都应该正常。

每个学生都有一个列表,每个课程都有一个列表

schedule [0] .Course有Id 1 时间表[0]。课程有Id 6

Id 14的学生将这两门课程列入其中。

仍然linq查询不会返回此学生。可能这是因为它不是同一个参考当然它不会在.Contains()找到匹配?

这让我完全疯狂,因为我尝试过的每一种方式都不会在有比赛时返回任何结果......

enter image description here

3 个答案:

答案 0 :(得分:1)

您正在Course进行比较reference type。这意味着对象指向内存中的位置而不是Course对象本身的实际值,因此您永远不会得到匹配,因为学生的课程和时间块查询中的课程都是以不同的方式进行的记忆的领域。

您应该使用value type进行比较,例如课程ID。值类型是实际数据本身,因此使用类似int(对于整数)的内容将比较实际数值。设置为相同数字的两个不同int变量将导致相等。

您还可以修改比较以接受任意数量的课程,而不仅仅是两个,以便使用它更加灵活。

if (schedules.Count() > 1)
{
    var scheduleCourseIds = schedules.Select(sch => sch.Course.Id).ToList();

    doublestudents = (from s in ctx.Students
                        let studentCourseIds = s.Courses.Select(c => c.Id)
                        where !scheduleCourseIds.Except(studentCourseIds).Any()
                        select s).ToList();

    Console.WriteLine(doublestudents.Count);
}

一些注意事项:

  1. 比较课程ID(假设这些ID是唯一的以及您在数据库中用来匹配它们的内容),以便您比较值类型并获得匹配。
  2. 使用Linq中的let关键字创建可在查询中使用的临时变量,使所有内容更具可读性。
  3. 使用包含另一组(found here)的所有元素的一组逻辑,这样您就可以拥有任意数量的重复课程。

答案 1 :(得分:0)

正如您所猜测的,这可能与参考平等有关。这是一个快速解决方法:

doublestudents =
    (from s in ctx.Students
    where s.Courses.Any(c => c.Id == schedules[0].Course.Id) && 
    s.Courses.Any(c => c.Id == schedules[1].Course.Id)
    select s).ToList();

请注意,我假设Course类有一个名为Id的属性,它是主键。根据需要更换它。

请注意,此代码假定有两个时间表。您需要处理代码以使其适用于任意数量的计划。

另一种方法是覆盖Equals类上的GetHashCodeCourse方法,以便根据它们的值(它们的属性值,可能是仅ID身份?)。

答案 2 :(得分:0)

问题是你的日程[0] .Course对象和新查询中的s.Courses是完全不同的。

您可以使用元素的键来评估您的相等条件/表达式,如:

        if (schedules.Count() > 1)
        {
            doublestudents = (from s in ctx.Students
                              where s.Courses.Any(x=> x.Key == schedules[0].Course.Key) && s.Courses.Any(x=> x.Key == schedules[1].Course.Key)
                              select s).ToList();

            Console.WriteLine(doublestudents.Count); <<< count results in 0 students.
        }

    }

为了实现这一目标,您需要包含

using System.Linq