如何定义User/Permission关系为M:M?

How to define User/Permission relationship as M:M?

ResourceAction 的关系为 M:M 通过 Permission 加入 table/separate实体。用户可以有许多命名权限。同一权限可能分配给多个用户。

如何定义User-Permission关系为M:M?在 EF 中会是什么样子?

编辑

这样映射对不对:

modelBuilder.Entity<User>()
    .HasMany(u => u.Permissions)
    .WithMany(p => p.Users)
    .Map(c => {
        c.MapLeftKey("ResourceId");
        c.MapLeftKey("ActivityId");
        c.ToTable("UserPermissions");
     });

前提是 Permission 是这样定义的:

public class Permission {
    public String Name { get; set; }

    public Int32 ResourceId { get; set; }
    public virtual Resource Resource { get; set; }

    public Int32 ActivityId { get; set; }
    public virtual Activity Activity { get; set; }

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

User像这样:

public class User : Entity {
    public String Username { get; set; }
    public String UserImagePath { get; set; }
    public String Password { get; set; }
    public virtual ISet<Permission> Permissions { get; set; }

    public User(String username, String password) {
        this.Username = username;
        this.Password = password;
        this.Permissions = new HashSet<Permission>();
    }
}

为了在 User 和 Permission 之间建立多对多关系,只需添加各自的集合。 在User中添加Permissions集合,在Permission中添加Users集合。

类似

User
...
...
<ICollection> Permissions


Permissions
....
....
<ICollection> Users

这有望添加一个新的 table,例如 PermissionsUsers 或 UsersPermissions。

要在 UserPermission 之间创建多对多关系,您需要创建两个 ICollection<> 类型的导航属性:

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Password { get; set; }

    public virtual ICollection<Permission> Permissions { get; set; }
}

public class Permission
{
    public int Id { get; set; }
    public string Name { get; set; }

    public int ResourceId { get; set; }
    public virtual Resource Resource { get; set; }

    public int ActionId { get; set; }
    public virtual Action Action { get; set; }

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

Code First 约定将识别多对多关系 并使用 tables 的适当键在数据库中构建一个连接 table 加盟。这些键都是连接 table 的主键和指向的外键 加入的 tables。新 table 的名称是通过组合以下名称创建的 类 它正在连接然后复数化结果。

如果您喜欢自己做,可以使用 Fluent Api。一种简单的方法是覆盖上下文的 OnModelCreating 方法。我在下面展示了一个例子,你的情况是怎样的:

 protected override void OnModelCreating(DbModelBuilder modelBuilder)
 {
        modelBuilder.Entity<User>().HasKey(p => p.Id);
        modelBuilder.Entity<User>().Property(u => u.Name).IsRequired();
        modelBuilder.Entity<User>().Property(u => u.Password).IsRequired();

        modelBuilder.Entity<Permission>().HasKey(p => p.Id);
        modelBuilder.Entity<Permission>().Property(u => u.Name).IsRequired();

        //configuring the many-to-many relationship
        modelBuilder.Entity<User>()
            .HasMany(u => u.Permissions)
            .WithMany(p => p.Users)
            .Map(c => c.ToTable("UserPermissions"));
 }

如您所见,您可以使用 Fluent Api 而不仅仅是指定您的关系。此外,如果需要某些 属性,您可以指定哪个属性将是主键,因此 on.All 您也可以使用 Data Annotations.[=18= 来完成这些事情]

这是我得到的:

DbContext

public class AppDbContext : DbContext {
    public DbSet<User> Users { get; set; }
    public DbSet<RoleResourceActivity> RoleResourceActivities { get; set; }
    public DbSet<Activity> Activities { get; set; }
    public DbSet<Resource> Resources { get; set; }
    public DbSet<Role> Roles { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder) {
        modelBuilder.Entity<Activity>().HasKey(i => i.Id);
        modelBuilder.Entity<Resource>().HasKey(i => i.Id);
        modelBuilder.Entity<User>().HasKey(i => i.Id);
        modelBuilder.Entity<RoleResourceActivity>().HasKey(i => new {
            i.ResourceId, 
            i.ActivityId, 
            i.RoleId
        });

        base.OnModelCreating(modelBuilder);
    }

    public AppDbContext() : base("AppDb") { 
        Database.SetInitializer<AppDbContext>(new AppDbContextInitializer());
    }
}

型号

public class RoleResourceActivity {
    public Int32 ResourceId { get; set; }
    public virtual Resource Resource { get; set; }

    public Int32 ActivityId { get; set; }
    public virtual Activity Activity { get; set; }

    public Int32 RoleId { get; set; }
    public virtual Role Role { get; set; }
}

public class User {
    public Int32 Id { get; set; }
    public String Username { get; set; }
    public String UserImagePath { get; set; }
    public String Password { get; set; }

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

    public User(String username, String password) : this() {
        this.Username = username;
        this.Password = password;
    }

    protected User() { 
        this.Roles = new HashSet<Role>();
    }
}

public class Role {
    public Int32 Id { get; set; }
    public String Name { get; set; }
    public virtual ISet<User> Users { get; set; }
    public virtual ISet<RoleResourceActivity> RoleResourceActivities { get; set; }

    public Role(String name) : this() { 
        this.Name = name;
    }

    protected Role() {
        this.Users = new HashSet<User>();
        this.RoleResourceActivities = new HashSet<RoleResourceActivity>();
    }
}

public class Resource {
    public Int32 Id { get; set; }
    public String Name { get; set; }
    public virtual ISet<RoleResourceActivity> RoleResourceActivities { get; set; }

    public Resource(String name) : this() {
        this.Name = name;
    }

    protected Resource() {
        this.RoleResourceActivities = new HashSet<RoleResourceActivity>();
    }
}

public class Activity {
    public Int32 Id { get; set; }
    public String Name { get; set; }
    public virtual ISet<RoleResourceActivity> RoleResourceActivities { get; set; }

    public Activity(String name) : this() {
        this.Name = name;
    }

    protected Activity() {
        this.RoleResourceActivities = new HashSet<RoleResourceActivity>();
    }
}