Linq to SQL Join允许Nulls当我不想要那个时

时间:2018-05-10 16:38:10

标签: c# entity-framework linq-to-sql

我编写了以下查询来加入几个表。 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))”

这与我想要的完全相反。如何使它进行正常的内部连接而不是尝试允许空值?

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

1 个答案:

答案 0 :(得分:3)

  

这与我想要的完全相反。如何使它进行正常的内部连接而不是尝试允许空值?

背后的理由是,在C#null == null中评估为true,而在SQL中,它评估为NULL(并且基本上是FALSE的句柄)。因此,EF试图模拟C#行为,以获得与在LINQ to Objects中运行相同查询时相同的结果。

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

[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