Внешнее соединение с запросом linq в EF Core 3 не работает - PullRequest
3 голосов
/ 05 марта 2020

Я занимаюсь разработкой футбольного приложения ASP. Net Core MVC. Я пытаюсь разобраться в EF Core, поскольку все, что я делал ранее, было прямым ADO. Net.

В моей базе данных есть таблица для игроков, таблица для MatchEvents и таблица соединений для создания отношения «многие ко многим», которая называется PlayerMatchEvents.

enter image description here

Я пытаюсь получить ВСЕХ Игроков вместе с их ролью в MatchEvent для конкретного MatchEvent, включая Игроков, которые не участвуют в этом матче. Другими словами, внешнее объединение.

Все мои исследования приводят к одному и тому же решению: объединение группы во временную переменную и использование DefaultIfEmpty (), но я просто не могу заставить его работать!

Код, с которым я сейчас работаю:

from p in Players
join pme in PlayerMatchEvents
on p.ID equals pme.PlayerID
into temp
from t in temp.DefaultIfEmpty() where t.MatchEventID ==2
select new
{
    PlayerFirstName = p.FirstName,
    PlayerLastName = p.LastName,
    Attendance = t == null ? null : t.PlayerMatchAttendanceDetail.Description

}

Приведенный выше код дает те же результаты, что и внутреннее соединение - т.е. возвращаются только те игроки, которые уже связаны с MatchEvent 2. Это потому, что он создает следующее SQL с предложением WHERE, отфильтровывающим строки, которые я хочу сохранить ...

SELECT [p].[FirstName] AS [PlayerFirstName], [p].[LastName] AS [PlayerLastName], [p1].[Description] AS [Attendance]
FROM [Players] AS [p]
LEFT JOIN [PlayerMatchEvents] AS [p0] ON [p].[ID] = [p0].[PlayerID]
LEFT JOIN [PlayerMatchAttendanceDetail] AS [p1] ON [p0].[PlayerMatchAttendanceDetailID] = [p1].[PlayerMatchAttendanceDetailID]
WHERE [p0].[MatchEventID] = 2
GO

Я пытаюсь достичь EF-эквивалента этого:

SELECT [p].[FirstName] AS [PlayerFirstName], [p].[LastName] AS [PlayerLastName], [p1].[Description] AS [Attendance]
FROM [Players] AS [p]
LEFT JOIN [PlayerMatchEvents] AS [p0] ON [p].[ID] = [p0].[PlayerID] AND [p0].[MatchEventID] = 2
LEFT JOIN [PlayerMatchAttendanceDetail] AS [p1] ON [p0].[PlayerMatchAttendanceDetailID] = [p1].[PlayerMatchAttendanceDetailID]
GO

Помещение критериев MatchEventID в объединение вместо предложения WHERE возвращает ВСЕХ игроков, включая тех, кто не связан с MatchEvent, чего я и хочу. Я могу сделать это в SQL, но я просто не могу понять, как это сделать в EF Core с запросами Linq.

Обновление:

Спасибо Ивану Стоев, исправленная (и протестированная) версия:

from p in Players
join pme in PlayerMatchEvents
on new { PlayerId = p.ID, MatchEventID = 2 } equals new { PlayerId = pme.PlayerID, MatchEventID = pme.MatchEventID }
into temp
from t in temp.DefaultIfEmpty() 
select new
{
    PlayerFirstName = p.FirstName,
    PlayerLastName = p.LastName,
    Attendance = t == null ? null : t.PlayerMatchAttendanceDetail.Description
}

1 Ответ

1 голос
/ 05 марта 2020

Стандартный способ LINQ для наложения критериев MatchEventID на объединение - Объединение с использованием составных ключей , например

on new { PlayerID = p.ID, MatchEventID = 2 } equals new { pme.PlayerID, pme.MatchEventID }

В EF Core мы обычно используем свойства навигации, а также перед выполнением объединения мы можем перевести sh внешний предикат в подзапрос справа, но вышеприведенный пример является ближайшим эквивалентом ручного соединения LINQ для SQL соединения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...