【问题标题】:Broken LINQ query with ternary expression带有三元表达式的损坏的 LINQ 查询
【发布时间】:2023-03-31 12:01:02
【问题描述】:

我有这个查询来获取文章列表。如果一篇文章IsLocked,它应该只包含在列表中,如果它是由登录的管理员用户创建的:

List<Article> articles = await db
    .Articles
    .Where(a => a.IsLocked
        ? a.CreatedBy.Id == LoggedInAdminUserId
        : true)
    .ToListAsync();

但就像现在一样,任何登录的管理员用户都可以看到所有锁定的文章,无论它们是谁创建的。

我应该如何修改我的查询?

** 编辑 **

上面的查询是一个缩短的版本。这是完整的查询:

List<Article> dbm = await db.Articles
    .Where(s => 
        (!s.IsLocked || s.CreatedBy.Id == LoggedInAdminUserId) &&
        s.Title.Contains(search) ||
        s.PreTitle.Contains(search) ||
        s.Preamble.Contains(search) ||
        s.MainText.Contains(search) ||
        s.CreatedBy.Member.FirstName.Contains(search) ||
        s.CreatedBy.Member.LastName.Contains(search) ||
        s.EditedBy.Member.FirstName.Contains(search) ||
        s.EditedBy.Member.LastName.Contains(search) ||
        s.FrontPageItem.PublishedBy.Member.FirstName.Contains(search) ||
        s.FrontPageItem.PublishedBy.Member.LastName.Contains(search)
    )
    .Include(f => f.FrontPageItem)
    .Include(e => e.CreatedBy)
        .ThenInclude(m => m.Member)
    .Include(e => e.EditedBy)
        .ThenInclude(m => m.Member)
    .Include(p => p.PublishReadyBy)
        .ThenInclude(m => m.Member)
    .Include(o => o.ArticleOperations)
    .OrderByDescending(s => s.DateCreated)
    .ToListAsync();

编辑 2

好的,所以我想已经很晚了,而且我的眼睛真的眯着。在所有 .Contains() 周围添加一组 () 就可以了:

.Where(s => 
    (!s.IsLocked || s.CreatedBy.MemberId == AdminUserMemberId) &&
    (s.Title.Contains(search) ||
    s.PreTitle.Contains(search) ||
    s.Preamble.Contains(search) ||
    s.MainText.Contains(search) ||
    s.CreatedBy.Member.FirstName.Contains(search) ||
    s.CreatedBy.Member.LastName.Contains(search) ||
    s.EditedBy.Member.FirstName.Contains(search) ||
    s.EditedBy.Member.LastName.Contains(search) ||
    s.FrontPageItem.PublishedBy.Member.FirstName.Contains(search) ||
    s.FrontPageItem.PublishedBy.Member.LastName.Contains(search))
)

【问题讨论】:

  • 您可以使用!a.IsLocked || a.CreatedBy.Id == LoggedInAdminUserId 简化三元的布尔表达式,但您的逻辑看起来是正确的。我假设每个管理员用户对 LoggedInAdminUserId 有不同的值?
  • 强烈推荐使用 AND 和 OR 来组合表达式,而不是使用条件表达式。阅读 !a.IsLocked || a.CreatedBy.ID == LoggedInAdminUserId 比你所拥有的更具可读性,即使它们在语义上是相同的。
  • IdLoggedInAdminUserId 属性的类型是什么?
  • @JonathonChase 我尝试用!s.IsLocked || s.CreatedBy.Id == LoggedInAdminUserId 替换表达式,但结果是一样的。是的,每个管理员用户都有一个唯一的LoggedInAdminUserId
  • @DervişKayımbaşıoğlu CreatedBy.MemberIdintLoggedInAdminUserIdint?。但即使我投到int,我也会得到相同的结果。

标签: c# linq asp.net-core


【解决方案1】:

看看你的完整表达,布尔逻辑很清楚问题。

(!s.IsLocked || s.CreatedBy.Id == LoggedInAdminUserId) &&
s.Title.Contains(search) ||
s.PreTitle.Contains(search) ||
... more

您正在检查文章是否已解锁或用户是否是创建者/管理员,然后忽略该结果以获取所有 OR 表达式的第一个积极响应。

解决方案是像这样使用括号:

(!s.IsLocked || s.CreatedBy.Id == LoggedInAdminUserId) &&
(s.Title.Contains(search) ||
s.PreTitle.Contains(search) ||
... more)

【讨论】:

    【解决方案2】:

    根据您编辑的问题,您有 AND/OR 优先级问题。您的 AND/OR 逻辑有问题。

    false && true || false || true || ....
    

    其实是

    (false && true) || false || true || ...
    

    结果为@​​987654323@

    【讨论】:

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