Linq to SQL Join Allowing Nulls When I don't want that
Linq to SQL Join Allowing Nulls When I don't want that
我编写了以下查询来连接几个表。 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 而不是试图预测我不知道的东西'要求。
That is the exact opposite of what I want. How do I make it do a normal inner join and not try to allow for null values?
背后的原因是,在 C# 中,null == null
计算为 true
,而在 SQL 中,它计算为 NULL
(并且基本上像 FALSE
).因此 EF 正在尝试模拟 C# 行为以获得与您在 LINQ to Objects 中 运行 相同查询相同的结果。
这是默认的 EF6 行为。它由 UseDatabaseNullSemantics
属性 控制,所以如果你想使用 SQL 行为,你应该在你的 DbContext
派生 [=] 中将它设置为 true
40=] 构造函数或来自外部:
[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
.
我编写了以下查询来连接几个表。 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 而不是试图预测我不知道的东西'要求。
That is the exact opposite of what I want. How do I make it do a normal inner join and not try to allow for null values?
背后的原因是,在 C# 中,null == null
计算为 true
,而在 SQL 中,它计算为 NULL
(并且基本上像 FALSE
).因此 EF 正在尝试模拟 C# 行为以获得与您在 LINQ to Objects 中 运行 相同查询相同的结果。
这是默认的 EF6 行为。它由 UseDatabaseNullSemantics
属性 控制,所以如果你想使用 SQL 行为,你应该在你的 DbContext
派生 [=] 中将它设置为 true
40=] 构造函数或来自外部:
[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
.