EF 4 Code First и M2M2M - PullRequest
       34

EF 4 Code First и M2M2M

1 голос
/ 21 марта 2011

Используя Entity Framework 4 и сначала код, как бы я создал модель, которая поддерживает этот сценарий:

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

Пример:

Я хотел бы сказать: «Дай мне Лизу», и ответ возвращает объект пользователя для Лизы с группами, к которым она принадлежит. Для каждой группы есть свойство списка со всеми ролями, которые она имеет для этой конкретной группы

Может кто-нибудь помочь мне сначала смоделировать это, используя код, любая справка / примеры кода, было бы здорово!

/ С уважением, Винблад

1 Ответ

2 голосов
/ 21 марта 2011

Редактировать: вот новая модель для вашего требования.

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

Как описано в коде, есть небольшой недостаток. Вы можете избежать этого недостатка, обеспечив целостность данных в БД с помощью дополнительных FK, которые не могут быть смоделированы в первую очередь кодом. Вы можете использовать пользовательский инициализатор, чтобы добавить этот 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])");
    }
}

Просто добавьте это в инициализацию вашего приложения (только для отладки - приложение не должно быть в состоянии отбросить свою базу данных в выпуске):

Database.SetInitializer(new CustomInitializer());
...