LINQ Приєднуйтесь до декількох умов у пункті On


93

Я намагаюся реалізувати запит у 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 про те, як це зробити.


Відповідна відповідь тут із використанням синтаксису
лямбди

Відповіді:


130

Вам просто потрібно назвати анонімну властивість однаковою з обох сторін

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

1
@svick - Використання анонімних типів дозволяє приєднатися за кількома критеріями. Потрібно лише переконатися, що назви властивостей збігаються для обох типів. Не впевнені, звідки береться плутанина?
Aducci

Плутанина полягає в тому, що це насправді має більше сенсу, оскільки дві рівності приєднуються and, а не одна рівність якогось "дивного" об'єкта. І на підтвердження моєї думки, ваш код помилковий. Для того, щоб це працювало, вам довелося б мати trueліву сторону і t2.Completeправу.
svick

1
Дякую Адуччі. Мені довелося помінятися сторонами в запиті, щоб правильно зрозуміти контекст, але це спрацювало. Ця проблема спрощена, і в моїй реальній проблемі це не просто SecondProperty є true або false, SecondProperty є цілим числом, і я використовую AND SecondProperty IN (123, 456). Я перейду до цього виклику, і будь-яка допомога, яку ви можете надати, буде вам вдячна.
Куєнда

@svick - Хороший улов, я змінив порядок t2.Completed і справжнє значення. Я додав ще одне рішення, яке може бути для вас менш дивним.
Aducci

39

Ось вам:

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

Ви не можете зробити це так. joinПоложення (і Join()метод розширення) підтримує тільки equijoins. Це також причина, чому вона використовує, equalsа ні ==. І навіть якби ви могли зробити щось подібне, це не спрацювало б, оскільки joinце внутрішнє, а не зовнішнє об’єднання.


Зовнішнє приєднання не просилося, і (див. Інші відповіді), очевидно, ви можете.
edc65

0

Це чудово працює для 2 таблиць. У мене є 3 таблиці, і за реченням потрібно пов’язати 2 умови з 3 таблиць. Мій код:

з p в _dbContext.Products приєднується до pv в _dbContext.ProductVariants на p.ProduktId дорівнює pv.ProduktId приєднується jpr в leftJoinQuery на новому {VariantId = pv.Vid, ProductId = p.ProduktId} дорівнює new {VariantId =VprantID ProductId = jpr.Price.ProduktID} у lj

Але його показ помилки на цьому етапі: приєднання pv у _dbContext.ProductVariants на p.ProduktId дорівнює pv.ProduktId

Помилка: тип одного з виразів у реченні join є неправильним. Не вдалося зробити висновок типу під час виклику "GroupJoin".

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.