【问题标题】:C# LINQ .Contains returns empty?C# LINQ .Contains 返回空?
【发布时间】:2016-03-13 16:09:39
【问题描述】:

对于学校项目,我需要过滤同时注册了多个课程的学生。我不想通过过程/视图查询数据库,而是想使用 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.
            }

        }

在调试时似乎一切正常。

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

schedules[0].Course 的 ID 为 1 schedules[0].Course 的 ID 为 6

ID 为 14 的学生的列表中有这两个课程。

linq 查询仍然没有返回这个学生。这可能是因为它不是同一个引用,当然它不会在 .Contains() 中找到匹配项吗?

这让我完全发疯,因为我尝试的每一种方式都不会在匹配时返回任何结果......

【问题讨论】:

    标签: c# linq contains


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

    【讨论】:

      【解决方案2】:

      问题是您的 schedule[0].Course 对象和新查询中的 s.Course 完全不同。

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

              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
      

      【讨论】:

      • 你的答案大同小异,也正确。谢谢! :)
      • 你是对的,原因是第一个答案是在我写我的时候发布的。
      【解决方案3】:

      如您所料,这可能与引用相等有关。这是一个快速修复:

      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 的属性,它是主键。根据需要更换它。

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

      另一种方法是覆盖Course 类上的Equals 和GetHashCode 方法,以便根据它们的值(它们的属性值,可能仅是ID 属性?)比较这种类型的对象。

      【讨论】:

      • 谢谢!它们确实是不同的对象。为此目的覆盖 Equals 或 GetHashCode 感觉是非常糟糕的做法。 .任何诀窍:)
      • 不客气。你是对的,我也不会在这种情况下覆盖这些方法。
      猜你喜欢
      • 2022-08-09
      • 1970-01-01
      • 2011-02-22
      • 1970-01-01
      • 2016-05-18
      • 1970-01-01
      • 2012-11-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多