开发者

EF 4 Code First and M2M2M

Using Entity Framework 4 and code first how would I create a model that supports this scenario:

In an application, there are users, each user belongs to one or more groups and for each group the user can have one or more roles.

Example:

I would like to be able to say, "give me Lisa", and the response returns a user object for lisa, with the groups she belongs to. For each group there is a list property with all the roles she has for that particular g开发者_运维百科roup

Can anyone help me model this using code first, any help/code samples, would be great!

/Best regards Vinblad


Edit: Here is new model for your requirement.

public class User
{
    public virtual int Id { get; set; }
    public virtual ICollection<UserPermission> Permissions { get; set; }
}

// Permission is extended junction table to model M:N between 
// User and Group but in addition it contains relation to Roles.
// The ony disadvantage is that this model doesn't control that
// role in the collection is also the role related to group. You
// must either enforce it in application logic or create some additional
// database construct to check it.
public class UserPermission
{
    public virtual int UserId {  get; set; }
    public virtual int GroupId { get; set; }

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

public class Group
{
    public virtual int Id { get; set; }
    public virtual ICollection<UserPermission> UserPermissions { get; set; }
    public virtual ICollection<Role> Roles { get; set; }
}


public class Role
{
    public virtual int Id { get; set; }
    public virtual ICollection<Group> Groups { get; set; }
    public virtual ICollection<UserPermission> UserPermissions { get; set; }
}

public class Context : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<Group> Groups { get; set; }
    public DbSet<Role> Roles { get; set; }
    public DbSet<UserPermission> UserPermissions { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        // Permission has composite key
        modelBuilder.Entity<UserPermission>()
            .HasKey(p => new {p.UserId, p.GroupId});

        // Permission doesn't have navigation property to user
        modelBuilder.Entity<User>()
            .HasMany(u => u.Permissions)
            .WithRequired()
            .HasForeignKey(p => p.UserId);

        modelBuilder.Entity<Group>()
            .HasMany(g => g.UserPermissions)
            .WithRequired(p => p.Group)
            .HasForeignKey(p => p.GroupId);
    }
}

As described in code there is small disadvantage. You can avoid the disadvantage by enforcing data integrity in DB by additional FK which can't be modeled by code first. You can use custom initializer to add that FK:

public class CustomInitializer : DropCreateDatabaseIfModelChanges<Context>
{
    protected override void Seed(Context context)
    {
        context.Database.ExecuteSqlCommand(
            @"ALTER TABLE [dbo].[RoleUserPermissions]  
             WITH CHECK ADD CONSTRAINT [FK_RoleUserPermissions_RoleGroups] 
             FOREIGN KEY([Role_Id], [UserPermission_GroupId])
             REFERENCES [dbo].[RoleGroups] ([Role_Id], [Group_Id])");
    }
}

Just add this to your application initialization (only for debug - application should not be able to drop its database in release):

Database.SetInitializer(new CustomInitializer());
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜