【问题标题】:How to write a an EF query involving a many to many relationship如何编写涉及多对多关系的 EF 查询
【发布时间】:2011-08-23 16:27:09
【问题描述】:

我对使用实体框架还是很陌生,我很难理解如何编写使用多对多关系的查询。我有 3 个实体。 角色用户安全。一个Role可以有多个Securables,一个Securable可以分配给多个Roles。一个角色可以有多个用户,一个用户可以有多个角色

我的问题是:我将如何编写一个查询,为给定的用户 ID 提供不同的 Securables 列表?

这是我的模型,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; }
}

【问题讨论】:

    标签: c# .net entity-framework entity-framework-4.1


    【解决方案1】:

    未经测试,但我想它会是这样的:

    var context = new DbContext();
    var result = context.Securables
                        .Where(s => s.Roles
                                     .Any(r => r.Users
                                                .Any(u => u.UserId = userId)))
                        .Distinct();
    

    【讨论】:

    • 这看起来像个赢家,我明天测试一下
    【解决方案2】:

    像这样?

    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();
    

    这将在翻译后的 SQL 中使用INNER JOIN:-

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

    使用WHERE EXISTS,在我们的基准测试中它比查询两次

    与往常一样,如果您有性能问题,我建议您进行分析。您的数据的结果可能会有所不同。 如果你不关心分析,你也不关心优化!

    【讨论】:

    • 嗯,简单的解决方案,但我认为这只有在启用延迟加载时才有效?这也需要两个 sql 查询,一个是获取用户,第二个是获取安全对象?
    • 如果这是性能瓶颈,您可以在加载用户时预先加载角色和安全对象。不过,除非您显示用户列表,否则我可能不会打扰。
    • 不,这个查询工作正常,没有延迟加载。它甚至可以在 EF 1 中使用。急切加载也无济于事;没关系。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-11
    • 2017-09-03
    • 1970-01-01
    • 2019-01-19
    • 2010-09-27
    • 1970-01-01
    • 2011-12-20
    相关资源
    最近更新 更多