Как написать запрос EF, включающий отношение многие ко многим - PullRequest
2 голосов
/ 23 августа 2011

Я довольно новичок в использовании структуры сущностей, и у меня возникли проблемы с тем, как разобраться в том, как написать запрос, который использует отношения многие ко многим.У меня есть 3 лица. Роль , Пользователь и Защищенный .A Role может иметь несколько Securables , а Securable может быть назначено множеству Roles . Роль может иметь несколько пользователей , а Пользователь может иметь несколько ролей .

Мой вопрос: Как мне написать запрос, который дал бы мне отдельный список защищаемых объектов для данного идентификатора пользователя?

Вот моя модель, гдеEF автоматически создает таблицы ссылок для меня.

public class SecurityContext : DbContext
{
    public DbSet<User> Users { get; set; }

    public DbSet<Role> Roles { get; set; }

    public DbSet<Securable> Securables { get; set; }
}

public class User 
{
    public Guid UserId { get; set; }

    public string Forename { get; set; }

    public string Surname { get; set; }

    public string Username { get; set; }

    public string Password { get; set; }

    public virtual ICollection<Role> Roles { get; set; }
}

public class Securable
{
    public Guid SecurableId { get; set; }

    public string Name { get; set; }

    public virtual ICollection<Role> Roles { get;set;}
}

public class Role
{
    public Guid RoleId { get; set; }

    public string Name { get; set; }

    public virtual ICollection<Securable> Securables { get; set; }

    public virtual ICollection<User> Users { get; set; }
}

Ответы [ 2 ]

2 голосов
/ 23 августа 2011

Непроверенный, но с моей головы это будет примерно так:

var context = new DbContext();
var result = context.Securables
                    .Where(s => s.Roles
                                 .Any(r => r.Users
                                            .Any(u => u.UserId = userId)))
                    .Distinct();
1 голос
/ 23 августа 2011

Как это?

User user = ...;
IEnumerable<Securable> securablesForUser =
  user.Roles.SelectMany(x => x.Securables).Distinct();

Обновление: -

После работы над проектом, где это было действительно узким местом производительности, я исследовал более глубоко и обнаружил, чтоследующий запрос LINQ генерирует лучший SQL (для наших данных): -

IEnumerable<Securable> securablesForUser =
    context.Users.Where(x => x.UserId == userId)
                 .SelectMany(x => x.Roles)
                 .SelectMany(x => x.Securables)
                 .Distinct();

Это будет использовать INNER JOIN в переведенном SQL-запросе: -

IEnumerable<Securable> securablesForUser = context.Securables.Where(
    x => x.Roles.Any(y => y.Users.Any(z => z.UserId == userId))).Distinct();

использует WHERE EXISTS который в нашем тесте был медленнее , чем запрос дважды.

Как всегда, если у вас есть проблемы с производительностью, я рекомендую профилирование.Результаты с вашими данными могут отличаться. Если вам не достаточно профилирования, вам не достаточно оптимизировать!

...