Получить проекты только с одним администратором, который является данным пользователем - PullRequest
1 голос
/ 10 января 2020

У меня есть следующие объекты:

public class Project {
  public Int32 Id { get; set; }
  public ICollection<ProjectRole> ProjectRoles { get; set; }
}

public class User {
  public Int32 Id { get; set; }
  public ICollection<ProjectRole> ProjectRoles { get; set; }
}

public class ProjectRole {
  public Int32 ProjectId { get; set; }
  public Int32 UserId { get; set; }
  public String Role { get; set; }
  public Project Project { get; set; }
  public User User { get; set; }
}

Учитывая userId Мне нужно найти все проекты, которые:
1. Имеют только один ProjectRole с Role равным Admin;
2. UserId из Admin равно заданному userId.

var userId = 1;

var projects = context.Projects.Where(x => x.ProjectRoles.Count(y => y.Role == "Admin") == 1 && ??

Я начал с того, что получил все проекты, у которых только одна роль равна Admin.

Мне не хватает, чтобы убедиться, что UserId в ProjectRole равно userId.

Как я могу это сделать?

Ответы [ 2 ]

1 голос
/ 11 января 2020

Проблема более интересна, чем кажется на первый взгляд, главным образом потому, что существует много простых решений, но все они должны выполнить 2 подзапроса на проект, чтобы удовлетворить 2 требования.

Например, поскольку Условие

x.ProjectRoles.Count(y => y.Role == "Admin")

обеспечивает наличие только 1 администратора на проект, дополнительное условие, например

&& x.ProjectRoles.Any(y => y.Role == "Admin" && y.UserId == userId)

или

&& x.ProjectRoles.FirstOrDefault(y => y.Role == "Admin").UserId == userId

или

&& x.ProjectRoles.Where(y => y.Role == "Admin").Select(y => y.UserId).Contains(userId)

будет гарантировать, что единственным администратором является данный пользователь.

Другим способом является использование таких критериев, как этот

x.ProjectRoles.Any(y => y.Role == "Admin" && y.UserId == userId)
    && !x.ProjectRoles.Any(y => y.Role == "Admin" && y.UserId != userId)

Другими словами, проект имеет данного пользователя в качестве администратора и не имеет другие администраторы.

На самом деле условие y.UserId == userId может быть удалено

x.ProjectRoles.Any(y => y.Role == "Admin")
    && !x.ProjectRoles.Any(y => y.Role == "Admin" && y.UserId != userId)

, т.е. у проекта есть администраторы, а также нет других администраторов, кроме данного пользователя, следовательно, у него есть только 1 администратор и он является данным пользователем.

В любом случае, как уже упоминалось в начале, все они выполняют 2 подзапроса на проект. Теперь, если вам интересно (и это интересная часть для меня), если это будет достигнуто с помощью одного подзапроса, ответ - да, с условием, подобным этому:

x.ProjectRoles.Where(y => y.Role == "Admin")
    .Min(y => y.UserId == userId ? (int?)1 : 0) == 1

Вот почему. После предложения Where у нас есть набор администраторов проекта. Теперь выражение

.Min(y => y.UserId == userId ? 1 : 0)

вернет

  • null, когда набор пуст (администраторов нет)
  • 0, если есть Admin, кроме данный пользователь
  • 1, когда данный пользователь является администратором, а других администраторов нет

Как мы видим, только возвращаемое значение 1 удовлетворяет обоим требованиям, следовательно, == 1 достигнет желаемой фильтрации.

0 голосов
/ 11 января 2020

Попробуйте это:

context.ProjectRoles
       .GroupBy(p => new { p.Role, p.UserId })
       .Where(g => g.Key.Role == "Admin" &&
                   g.Count() == 1 &&
                   g.All(z => z.UserId == userId)
             );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...