Использование нескольких типов пользователей в ASP.NET Identity

Рейтинг: 5Ответов: 1Опубликовано: 19.04.2015

В приложении должно присутствовать несколько типов учётных записей пользователей и у каждой должен быть свой набор полей. Одним из вариантов я вижу создание иерархии наследования:

public class ApplicationUser : IdentityUser
{
    public string Name { get; set; }
    public string Surname { get; set; }
    public IImage AvatarImage { get; set; }
    public bool IsBlocked { get; set; }
    public School School { get; set; }

    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        return userIdentity;
    }
}

public class StudentUser : ApplicationUser
{
    public TeachingType TeachingType { get; set; }
    public int Grade { get; set; }
}

public class TeacherUser : ApplicationUser
{
    public bool IsConfirmed { get; set; }
    public List<Subject> Subjects { get; set; }
}

Контекст я вижу таким:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }

    public DbSet<TeacherUser> TeacherUsers { get; set; }
    public DbSet<StudentUser> StudentUsers { get; set; }             
}

Есть ли способ научить Identity работать с этой иерархией и возвращать сущность пользователя нужного мне типа?

Ответы

▲ 2Принят

Identity в вашем случае использует самый обычный Entity Framework для хранения учетных записей пользователей - а Entity Framework всегда имел такую возможность.

Только контекст вы привели неправильный.

Независимо от способа хранения, DbSet должен быть один на иерархию и в нем должен храниться базовый класс.

А способов хранения - три:

  1. Table per Hierarchy (TPH) - все свалено в одну таблицу.
  2. Table per Type (TPT) - на каждый класс по таблице, их первичные ключи объединены отношениями вида 1 - (0..1).
  3. Table per Concrete class (TPC) - по таблице на каждый неабстрактный класс. Но DbSet при этом все равно один!

Для создания БД первого типа просто добавьте DbSet с базовым типом в контекст - все потомки будут свалены в ту же таблицу автоматически.

Если вам больше нравится второй тип - добавьте потомкам атрибут Table. Или перегрузите метод OnModelCreating, указав там примерно следующее:

modelBuilder.Entity<TeacherUser>().ToTable("TeacherUsers");
modelBuilder.Entity<StudentUser>().ToTable("StudentUsers");

Ну а если больше всего нравится третий тип - используйте вот такую конструкцию в том же методе:

modelBuilder.Entity<TeacherUser>().Map(m =>
{
    m.MapInheritedProperties();
    m.ToTable("TeacherUsers");
});

modelBuilder.Entity<StudentUser>().Map(m =>
{
    m.MapInheritedProperties();
    m.ToTable("StudentUsers");
});