Farther extending ApplicationUser class in ASP.NET MVC5 Identity system

5.6k views Asked by At

I'm creating a simple application for university where a student can make some type of request which is then processed by an employee of particular speciality.

I would like to use default MVC5 identity system and to extend the ApplicationUser class using TPH pattern. So I added the common properties to the ApplicationUser:

public class ApplicationUser : IdentityUser
    {
        [Required]
        public string FirstName { get; set; }
        [Required]
        public string LastName { get; set; }
        [Required]
        public string Email { get; set; }
    }

then I created two classes which inherits the ApplicationUser:

public class Student : ApplicationUser
    {
        public string PersonalNumber { get; set; }
        public bool Monitor { get; set; }
        public virtual Group Group { get; set; }
        public virtual ICollection<Request> Requests { get; set; }
    }

public class Employee : ApplicationUser
    {
        public virtual EmployeeSpeciality EmployeeSpeciality { get; set; }
        public virtual ICollection<Request> Requests { get; set; }
    }

what I currently want is to make both types of users register as a base Identity and to keep both in a single table as in the inheritance example on asp.net

As I thought, it would be enough to initialize user var in AccountController which is then passes to the UserManager as a Student or as an Employee. But after trying to register as a Student i'm getting this exception:

Exception Details: System.Data.SqlClient.SqlException: Invalid column name 'PersonalNumber'.
Invalid column name 'Monitor'.
Invalid column name 'EmployeeSpeciality_Id'.
Invalid column name 'Group_Id'.

My context class:

public class EntityContext : IdentityDbContext
    {
        public EntityContext()
            : base("DbConnection")
        {
        }

        public DbSet<ApplicationUser> ApplicationUsers { get; set; }
        public DbSet<Student> Students { get; set; }
        public DbSet<Employee> Employees { get; set; }
        ...
    }

and a part of controller's action:

public async Task<ActionResult> Register(RegisterViewModel model)
    {
        if (ModelState.IsValid)
        {
            var user = new Student()
            {
                UserName = model.UserName,
                FirstName = model.FirstName,
                LastName = model.LastName,
                Email = model.Email
            };
            var result = await UserManager.CreateAsync(user, model.Password);

I tried setting ApplicationClass to an abstract class, but no luck. Any help would be appreciated.

UPDATE: The problem wasn't in the code itself. I simply haven't dropped (or updated) the database after making these changes to the model. After it everything works just fine.

2

There are 2 answers

2
Suhas Joshi On

@Dragonheart: I tried this repro and it would work fine if you remove the DBSet declarations in you context class. The IdentityDbContext would handle you TPH pattern and add a Discriminator column in the table to differentiate the child classes.

2
Murat Yıldız On

As ApplicationUser is inherited from IdentityUser, remove it from your DbContext class. On the other hand, there is no need to create an abstract class (you can create if you prevent from creating a user except from Student or Employee classes. For more information you might have a look at Table-per-Hierarchy.

For Register part, try something like that:

Student user = new Student
{
    UserName = model.UserName,
    FirstName = model.FirstName,
    LastName = model.LastName,
    Email = model.Email
};
var result = UserManager.Create(user, model.Password);

Hope this helps...