【问题标题】:Outer join with linq query in EF Core 3 not workingEF Core 3 中带有 linq 查询的外部联接不起作用
【发布时间】:2020-03-06 00:55:24
【问题描述】:

我正在开发一个以足球为主题的 ASP.Net Core MVC Web 应用程序。我试图了解 EF Core,因为我之前所做的一切都是直接的 ADO.Net。

在我的数据库中,我有一个 Players 表、一个 MatchEvents 表和一个用于创建多对多关系的连接表,称为 PlayerMatchEvents。

我正在尝试为特定 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 的玩家。这是因为它正在使用 WHERE 子句创建以下 SQL,该子句过滤掉我想要保留的行...

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 中执行此操作,但我无法弄清楚如何使用 Linq 查询在 EF Core 中执行此操作。

更新:

感谢 Ivan Stoev,更正(和测试)的版本是:

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
}

【问题讨论】:

    标签: linq entity-framework-core


    【解决方案1】:

    将 MatchEventID 条件放在连接上的标准 LINQ 方法是 Join by using composite keys,例如

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

    在 EF Core 中我们通常使用导航属性,并且我们可以在执行连接之前将外部谓词推送到右侧子查询中,但上面是最接近 SQL 连接的 LINQ 手动连接。

    【讨论】:

    • 谢谢,成功了(尽管我不得不为右侧分配相同的名称以避免错误 CS1941:连接子句中的表达式之一不正确。类型推断失败在对“GroupJoin”的调用中,所以现在我有:在 new { PlayerId = p.ID, MatchEventID = 2 } 上等于 new { PlayerId = pme.PlayerID, MatchEventID = pme.MatchEventID }。我得看看在使用导航属性时——就像我说的,这对我来说是全新的!
    • 这只是我的左侧属性名称代码中的拼写错误(PlayerId 而不是PlayerID)。这个想法当然是匹配右侧的属性名称,您以不同的(不太简洁,但仍然有效)方式解决了它。
    • 我怎么没看到?谢谢。
    猜你喜欢
    • 2020-01-25
    • 1970-01-01
    • 2020-09-27
    • 2021-08-25
    • 2021-10-22
    • 2019-03-27
    • 1970-01-01
    • 2020-12-24
    • 2020-03-29
    相关资源
    最近更新 更多