2016-03-13 2 views
0

Для школьного проекта мне нужно отфильтровать студентов, которые подписались на несколько курсов в тот же момент времени. Вместо того, чтобы запрашивать DB через процедуры/представления, я хочу использовать LINQ для его фильтрации в памяти для обучения.C# LINQ .Contains возвращается пустым?

Все кажется хорошо в зависимости от отладчика, однако результат моего запроса 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. 
      } 

     } 

При отладке, кажется, все должно работать нормально.

Каждый студент имеет список, и каждый курс HSA списка

расписания [0] .Course имеет Id 1 графики [0] .Course имеет Id 6

Студент с идентификатором 14 имеет оба эти курсы в этом списке.

По-прежнему запрос linq не возвращает этого ученика. Может ли это быть потому, что это не та же ссылка, конечно, что он не найдет матч в .Contains()?

Это сводит меня с ума, так как совершенно всячески стараюсь этого не возвратит никаких результатов, пока есть результаты ...

enter image description here

ответ

1

Вы сравниваете на Course, которые это reference type. Это означает, что объекты указывают на местоположения в памяти, а не на фактические значения самого объекта Course, поэтому вы никогда не получите соответствия, потому что курсы ученика и курсы из запроса на блокировку времени хранятся в разных областях памяти.

Для сравнения необходимо использовать value type, например идентификатор курса. Типы значений - это фактические данные, поэтому использование чего-то вроде 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. Сравните идентификаторы курса (предполагается, что они являются уникальными и то, что вы используете, чтобы соответствовать их в базе данных), так что вы сравниваете типы значений и получить матч.
  2. Используйте ключевое слово let в Linq, чтобы создать временные переменные, которые вы можете использовать в запросе, и сделать все более читаемым.
  3. Используйте логику для одного набора, содержащего все элементы другого набора (found here), чтобы вы могли иметь любое количество дублированных курсов для соответствия.
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 и GetHashCode методы на Course класса, так что объекты данного типа сравниваются на основе их значений (значения их свойств, возможно, идентификатор собственности в одиночку?).

+0

Спасибо! На самом деле это были разные объекты. Для этой цели очень плохо, чтобы переопределить Equals или GetHashCode. . Любой трюк :) –

+0

Добро пожаловать. Вы правы, я бы не стал переопределять эти методы и для этого случая. –

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 
+0

Ваш ответ будет таким же, а также правильным. благодаря! :) –

Смежные вопросы