当我不想要的时候,Linq to SQL Join 允许 Nulls

Posted

技术标签:

【中文标题】当我不想要的时候,Linq to SQL Join 允许 Nulls【英文标题】:Linq to SQL Join Allowing Nulls When I don't want that 【发布时间】:2018-05-10 16:38:10 【问题描述】:

我编写了以下查询来连接几个表。 la.UserProfileId 由于某些不敬的原因可以为空。

当我编写等效的 SQL 语句时,此时我应该得到 0 条记录。

var result = (from e in _ctx.Employees
                     join la in _ctx.LoginAudits on e.UserProfile.Id equals la.UserProfileId.Value
                     where la.LoginDate >= fromDate
                     && e.Client.Id == clientID
                     select new
                     
                         la.Id,
                         employeeID = e.Id,
                         e.Client.DisplayName,
                         la.UserProfileId
                     ).ToList();

上面的 LINQ 代码生成下面的 SQL。

exec sp_executesql N'SELECT 
1 AS [C1], 
[Extent2].[Id] AS [Id], 
[Extent1].[Id] AS [Id1], 
[Extent3].[DisplayName] AS [DisplayName], 
[Extent2].[UserProfileId] AS [UserProfileId]
FROM   [dbo].[Employees] AS [Extent1]
INNER JOIN [dbo].[LoginAudits] AS [Extent2] ON ([Extent1].[UserProfile_Id] = [Extent2].[UserProfileId]) OR (([Extent1].[UserProfile_Id] IS NULL) AND ([Extent2].[UserProfileId] IS NULL))
INNER JOIN [dbo].[Clients] AS [Extent3] ON [Extent1].[Client_Id] = [Extent3].[Id]
WHERE ([Extent2].[LoginDate] >= @p__linq__0) AND ([Extent1].[Client_Id] = @p__linq__1)',N'@p__linq__0 datetime2(7),@p__linq__1 bigint',@p__linq__0='2018-02-09 11:11:29.1047249',@p__linq__1=37

如您所见,它包括“OR (([Extent1].[UserProfile_Id] IS NULL) AND ([Extent2].[UserProfileId] IS NULL))”

这与我想要的完全相反。如何让它做一个正常的内部连接,而不是尝试允许空值?

我可以通过在 WHERE 子句中添加 && la.UserProfileId != null 来解决这个问题,但理想情况下,我宁愿让 JOIN 表现得像普通的 INNER JOIN 一样,而不是试图预测我不要求的东西.

【问题讨论】:

模型中的字段是否可以为空?如果是这样,请尝试使用 e.UserProfile.Id.Value 代替? 【参考方案1】:

这与我想要的完全相反。如何让它做一个正常的内部连接,而不是尝试允许空值?

背后的原因是,在 C# 中,null == null 的计算结果为 true,而在 SQL 中,它的计算结果为 NULL(基本上像 FALSE 一样处理)。因此,EF 正在尝试模拟 C# 行为,以便获得与在 LINQ to Objects 中运行相同查询相同的结果。

这是默认的 EF6 行为。它由UseDatabaseNullSemantics 属性控制,因此如果要使用SQL 行为,应在DbContext 派生类构造函数中或从外部将其设置为true

[dbContext.]Configuration.UseDatabaseNullSemantics = true;

但这还不够。它影响所有比较运算符,但他们忘记将其应用于连接。解决方案是不使用 LINQ join 运算符,而是关联 where(EF 足够聪明,可以将其转换为 SQL JOIN)。

所以除了将UseDatabaseNullSemantics 设置为true,替换

join la in _ctx.LoginAudits on e.UserProfile.Id equals la.UserProfileId

from la in _ctx.LoginAudits where e.UserProfile.Id == la.UserProfileId

你会得到想要的INNER JOIN

【讨论】:

以上是关于当我不想要的时候,Linq to SQL Join 允许 Nulls的主要内容,如果未能解决你的问题,请参考以下文章

LINQ to SQL语句之Join

Linq to sql之left join运用示例

如何使用 LINQ to SQL 执行 CROSS JOIN?

LINQ to SQL Count/Sum/Min/Max/Avg Join

csharp 来自http://stackoverflow.com/questions/1122942/linq-to-sql-left-outer-join-with-multiple-join-c

Linq to SQL - 视图与存储过程