Search code examples
asp.netasp.net-mvc-5asp.net-identityentity-framework-migrations

EF Code First Migrations creating extra Column when Extending the Identity Role Class


I opened VS2013 and created an empty MVC project with identity 1, I wanted to extend Identity Role Class, adding an extra field to AspNetRoles, so I added this class to Models Folder:

  public class ApplicationRole : IdentityRole
    {
        public ApplicationRole() : base() { }
        public ApplicationRole(string name, string title)
            : base(name)
        {
            this.Title = title;
        }
        public virtual string Title { get; set; }
    }

then in PowerShell > enable-migrations>add-migration mig1 and it created below class:

public partial class mig1 : DbMigration
    {
        public override void Up()
        {
            CreateTable(
                "dbo.AspNetRoles",
                c => new
                    {
                        Id = c.String(nullable: false, maxLength: 128),
                        Name = c.String(nullable: false, maxLength: 256),
                        Title = c.String(),
                        Discriminator = c.String(nullable: false, maxLength: 128),  // The rogue column
                    })
                .PrimaryKey(t => t.Id)
                .Index(t => t.Name, unique: true, name: "RoleNameIndex");    
        {
         //Another tables         
   {

but as you can see migration created an extra column (Discriminator) that I don't know what is that.

it wasn't what I want so I commented it and for seeding in configuration class I added this codes:

protected override void Seed(another.Models.ApplicationDbContext context)
        {

            if (!context.Roles.Any(r => r.Name == "AppAdmin"))
            {
                var store = new RoleStore<ApplicationRole>(context);
                var manager = new RoleManager<ApplicationRole>(store);
                var role = new ApplicationRole { Name = "AppAdmin", Title = "Admin" };

                // Create: Create a role.    
                manager.Create(role);
            }
            if (!context.Roles.Any(r => r.Name == "Customer"))
            {
                var store = new RoleStore<ApplicationRole>(context);
                var manager = new RoleManager<ApplicationRole>(store);
                var role = new ApplicationRole { Name = "Customer",Title="usualuser" };

            // Create: Create a role.    
            manager.Create(role);
        }
    } 

then in PowerShell > update-database, and it threw an exception: "An error occurred while executing the command definition. See the inner exception for details. ---> System.Data.SqlClient.SqlException: Invalid column name 'Discriminator'"

EDITED: this my context

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

        public static ApplicationDbContext Create()
        {
            return new ApplicationDbContext();
        }
    }

Solution

  • Your context doesn't specify that you are using your custom role class so Entity Framework scans the project for any classes that inherit from the base IdentityRole class and assumes that you may want to use TPH (table per hierarchy) where it's possible to store both IdentityRole and ApplicationRole objects in the same DbSet. To do this, it adds a Discriminator column to distinguish what the type is.

    To fix this, your context should inherit from the other IdentityDbContext that allows you to specify the types. For example:

    public class ApplicationDbContext : 
        IdentityDbContext<ApplicationUser, ApplicationRole, string, 
            IdentityUserLogin, IdentityUserRole, IdentityUserClaim>
    {
        //Snip
    }