代码之家  ›  专栏  ›  技术社区  ›  Don Sartain

Linq到SQL连接允许在我不需要时使用null

  •  3
  • Don Sartain  · 技术社区  · 6 年前

    我编写了下面的查询来连接几个表。洛杉矶。由于某些不正当的原因,UserProfileId可以为Null。

    当我编写等效的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
    

    如您所见,它包括“或([Extent1][UserProfile\u Id]为NULL)和([Extent2][UserProfileId]为NULL))”

    这与我想要的恰恰相反。如何使其进行正常的内部联接,而不尝试允许空值?

    我可以通过添加&&洛杉矶。UserProfileId!=我的WHERE子句中为null,但理想情况下,我宁愿让连接像正常的内部连接一样工作,而不要试图预测我不需要的东西。

    1 回复  |  直到 6 年前
        1
  •  4
  •   Ivan Stoev    5 年前

    这与我想要的恰恰相反。如何使其进行正常的内部联接,而不尝试允许空值?

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

    这是默认的EF6行为。它由 UseDatabaseNullSemantics 属性,因此如果要使用SQL行为,应将其设置为 符合事实的 在您的 DbContext 派生类构造函数或来自外部:

    [dbContext.]Configuration.UseDatabaseNullSemantics = true;
    

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

    因此,除了设置 UseDatabaseNullSemantics 符合事实的 代替

    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