【问题标题】:Why does this LINQ query fail to work?为什么此 LINQ 查询无法工作?
【发布时间】:2016-10-26 12:37:09
【问题描述】:

我遇到了一个问题,我想了解它为什么会发生。一些帮助将不胜感激。

我正在使用实体框架核心,这是我在代码中的查询:

var user = await _db.User
      .Where(x => x.Email == username & x.Suspended == null)
      .Select(x => new
      {
           x.UserId,
           x.Password,
           x.Salt,
           Role = x.Role.Name
      })
      .SingleOrDefaultAsync();


此查询不会选择用户,但不会引发任何错误。如果我从 Where 子句中删除“x.Suspended”,它将返回用户。 “Suspended”是通过用户 ID 与用户表相关的表。用户 ID 在两个表中都是 PK,所以关系是 1 对 1。 我认为这个查询不会返回用户,因为 x.Suspended 为空。有人可以帮助我了解为什么会发生这种情况以及我可以做些什么来让它发挥作用。

更新: 好的,我使用了 SQL Server Profiler,这是通过实体框架转换的 sql:

exec sp_executesql N'SELECT [x.Suspended].[UserId], [x.Suspended].[RCD], [x.Suspended].[Reason], [x].[UserId], [x].[Password], [x].[Salt], [x.Role].[Name]
FROM [User] AS [x]
INNER JOIN [Role] AS [x.Role] ON [x].[RoleId] = [x.Role].[RoleId]
INNER JOIN [Suspended] AS [x.Suspended] ON [x].[UserId] = [x.Suspended].[UserId]
WHERE [x].[Email] = @__username_0',N'@__username_0 varchar(80)',@__username_0='some-username'

这里的问题是所有的一对一关系都被转换为 INNER JOIN。我该如何处理这个问题?提前致谢!

更新 2: 我开始认为这是 EF Core 中的一个错误。例如当我有这个时:

var user = await _db.User
      .Include(x => x.Role)
      .Include(x => x.Suspended)
      .Where(x => x.Email == username)
      .SingleOrDefaultAsync();

在分析器下,sql输出是这样的:

exec sp_executesql N'SELECT TOP(2) [x].[UserId], [x].[Email], [x].[FirstName], [x].[LastName], [x].[Password], [x].[Phone], [x].[RCD], [x].[RoleId], [x].[Salt], [s].[UserId], [s].[RCD], [s].[Reason], [r].[RoleId], [r].[Name]
FROM [User] AS [x]
LEFT JOIN [Suspended] AS [s] ON [s].[UserId] = [x].[UserId]
INNER JOIN [Role] AS [r] ON [x].[RoleId] = [r].[RoleId]
WHERE [x].[Email] = @__username_0',N'@__username_0 varchar(80)',@__username_0='user-email'

显然,“暂停”表是左连接而不是内连接。但是当我有这个时:

 var user1 = await _db.User
       .Include(x => x.Role)
       .Include(x => x.Suspended)
       .Where(x => x.Email == username & x.Suspended == null)
       .SingleOrDefaultAsync();

sql profiler下的sql是:

SELECT [x].[UserId], [x].[Email], [x].[FirstName], [x].[LastName], [x].[Password], [x].[Phone], [x].[RCD], [x].[RoleId], [x].[Salt], [x.Suspended].[UserId], [x.Suspended].[RCD], [x.Suspended].[Reason], [s].[UserId], [s].[RCD], [s].[Reason], [r].[RoleId], [r].[Name]
FROM [User] AS [x]
INNER JOIN [Suspended] AS [x.Suspended] ON [x].[UserId] = [x.Suspended].[UserId]
LEFT JOIN [Suspended] AS [s] ON [s].[UserId] = [x].[UserId]
INNER JOIN [Role] AS [r] ON [x].[RoleId] = [r].[RoleId]

真是一团糟:-D 我们到底是如何将“暂停”表加入两次,INNER 和 LEFT? WHERE 子句在哪里?

我想要的只是在 LINQ 中工作:

SELECT U.[UserId], U.[Password], U.[Salt], R.[Name] AS [Role]
FROM [ag].[dbo].[User] AS U
INNER JOIN [ag].[dbo].[Role] AS R ON U.[RoleId] = R.[RoleId]
LEFT JOIN [ag].[dbo].[Suspended] AS S ON U.[UserId] = S.[UserId]
WHERE U.[Email] = 'john.smith@gmail.com' AND S.[UserId] IS NULL

【问题讨论】:

  • 但是 INNER JOIN 将完全满足您的需求 - 删除带有 null Suspended 的行。唯一让我感到惊讶的是Role 表上的INNER JOIN,我相信这是由Select 子句中的x.Role.Name 引起的。试试Role = x.Role == null ? null : x.Role.Name,但我不确定这是否会有所帮助。
  • 用户和挂起的关系是1..0-1而不是1:1
  • 谢谢罗伯特,这里的想法是,如果用户被暂停,那么记录应该在“暂停”表中,并附上原因和日期。此查询用于身份验证,在用户通过身份验证并提供令牌(jwt)之前,我需要确保用户没有被暂停。 INNER join 在这里根本没有帮助。我确实理解他们为什么要这样设计。
  • 角色是一个自己喜欢的表 暂停与用户的一对一关系。唯一的区别是用户记录有 RoleId 列。似乎 EF 将所有一对一关系转换为内部连接。
  • 是的,因为所有 1:1 关系本质上都是内连接。

标签: c# linq async-await entity-framework-core


【解决方案1】:

你应该使用 &&

var user = await _db.User
      .Where(x => x.Email == username && x.Suspended != null)
      .Select(x => new
      {
           x.UserId,
           x.Password,
           x.Salt,
           Role = x.Role.Name
      })
      .SingleOrDefaultAsync();

【讨论】:

  • 也试过了,没用。
  • 嗯,Suspended 是否为空?如果它不为 null 则有效,但如果为 null 则无效。
  • 嗯,x.Suspended 是一个表(它自己的对象)。请参阅我发布的数据库的架构。它不是布尔值。
  • @Arman 可能需要从主表中检查您的suspended.userid 和userid
  • @Sajeetharan 如果用户已挂起,则该用户的 Suspended 表中应该有一条记录。此特定用户未挂起,因此该表中没有记录,因此在这种情况下 x.Suspended 为空。我可能需要查看分析器,看看发送到服务器的 sql 是什么。
【解决方案2】:

我是对的,这是一个错误,将在未来的 EF 核心版本中修复。这是 github 上的问题链接。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多