Соединение LINQ с несколькими условиями в предложении On

94

Я пытаюсь реализовать запрос в LINQ, который использует левое внешнее соединение с несколькими условиями в предложении ON.

Я буду использовать пример следующих двух таблиц: Project (ProjectID, ProjectName) и Task (TaskID, ProjectID, TaskName, Completed). Я хочу видеть полный список всех проектов с соответствующими задачами, но только те задачи, которые выполнены.

Я не могу использовать фильтр, Completed == trueпотому что он отфильтрует все проекты, у которых нет завершенных задач. Вместо этого я хочу добавить Completed == trueв предложение ON соединения, чтобы отображался полный список проектов, но отображались только выполненные задачи. В проектах без завершенных задач будет отображаться одна строка с нулевым значением для задачи.

Вот основа запроса.

from t1 in Projects
join t2 in Tasks
on new { t1.ProjectID} equals new { t2.ProjectID } into j1
from j2 in j1.DefaultIfEmpty()
select new { t1.ProjectName, t2.TaskName }

Как добавить && t2.Completed == trueв предложение on?

Кажется, я не могу найти документацию LINQ о том, как это сделать.

Kuyenda
источник
Связанный ответ здесь с использованием синтаксиса Lambda
StuartLC

Ответы:

132

Вам просто нужно назвать анонимное свойство одинаковым с обеих сторон.

on new { t1.ProjectID, SecondProperty = true } equals 
   new { t2.ProjectID, SecondProperty = t2.Completed } into j1

Основываясь на комментариях @svick, вот еще одна реализация, которая может иметь больше смысла:

from t1 in Projects
from t2 in Tasks.Where(x => t1.ProjectID == x.ProjectID && x.Completed == true)
                .DefaultIfEmpty()
select new { t1.ProjectName, t2.TaskName }
Адуччи
источник
2
Это кажется неочевидным способом сделать это. Не уверен, что пойму, что он должен делать.
svick 05
1
@svick - использование анонимных типов позволяет вам присоединиться по нескольким критериям. Вам просто нужно убедиться, что имена свойств совпадают для обоих типов. Не знаете, откуда взялась путаница?
Адуччи 05
Заблуждение состоит в том, что это действительно имеет больше смысла, когда соединяются два равенства and, а не одно равенство какого-то «странного» объекта. И чтобы доказать мою точку зрения, ваш код неверен. Чтобы он работал, у вас должны быть trueслева и t2.Completeсправа.
svick 05
1
Спасибо Адуччи. Мне пришлось поменять местами в запросе, чтобы понять контекст, но это сработало. Эта проблема упрощена, и в моей реальной проблеме не только SecondProperty истинно или ложно, SecondProperty является целым числом, и я использую AND SecondProperty IN (123, 456). Я перейду к этой задаче и буду очень признателен за любую помощь, которую вы могли бы оказать.
Kuyenda 05
@svick - Хороший улов, я поменял порядок t2.Completed и true value. Я добавил еще одно решение, которое может показаться вам менее странным.
Адуччи 05
40

Вот вам:

from b in _dbContext.Burden 
join bl in _dbContext.BurdenLookups on
new { Organization_Type = b.Organization_Type_ID, Cost_Type = b.Cost_Type_ID } equals
new { Organization_Type = bl.Organization_Type_ID, Cost_Type = bl.Cost_Type_ID }
Налан Мадхесваран
источник
Это выглядит более понятным.
Биджай Ядав
1

Вы не можете этого сделать. Предложение joinJoin()метод расширения) поддерживает только эквивалентные соединения. Это также причина, почему он использует, equalsа не ==. И даже если бы вы могли сделать что-то подобное, это не сработало бы, потому что joinэто внутреннее соединение, а не внешнее соединение.

Свик
источник
Внешнее соединение не запрашивалось, и (см. Другие ответы), очевидно, вы можете.
edc65
0

Это отлично работает для 2 таблиц. У меня есть 3 таблицы, и в статье нужно связать 2 условия из 3 таблиц. Мой код:

из p в _dbContext.Products присоединяются к pv в _dbContext.ProductVariants на p.ProduktId равны pv.ProduktId join jpr в leftJoinQuery на новом {VariantId = pv.Vid, ProductId = p.ProduktId} равняется new {VariantPrices.VariantId = jpr.Id. ProductId = jpr.Prices.ProduktID} в lj

Но на этом этапе отображается ошибка: присоединиться к pv в _dbContext.ProductVariants на p.ProduktId равно pv.ProduktId

Ошибка: неверный тип одного из выражений в предложении соединения. Не удалось определить тип при вызове GroupJoin.

OracleNovice
источник