taburetkin
taburetkin

Reputation: 313

extending PrimaryKey of IdentityUserRole in Identity 2

Is it possible to extend primary key of ApplicationUserRole by additional column?

by default there are two columns defined as primary key: UserId and RoleId

here is default implementation

public partial class ApplicationUserRole : IdentityUserRole<string>
{
    public virtual ApplicationUser User { get; set; }
    public virtual ApplicationRole Role { get; set; }
}

public class IdentityUserRole<TKey>
{
    public IdentityUserRole();

    // Summary:
    //     RoleId for the role
    public virtual TKey RoleId { get; set; }
    //
    // Summary:
    //     UserId for the user that is in the role
    public virtual TKey UserId { get; set; }
}

and the table in a db looks like

CREATE TABLE [dbo].[AspNetUserRoles](
    [UserId] [nvarchar](128) NOT NULL,
    [RoleId] [nvarchar](128) NOT NULL,
 CONSTRAINT [PK_dbo.AspNetUserRoles] PRIMARY KEY CLUSTERED 
(
    [UserId] ASC,
    [RoleId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

but i need more! :) i mean i want my model looks like

public partial class ApplicationUserRole : IdentityUserRole<string>
{

    public Guid ServiceId { get; set; }

    public virtual ApplicationUser User { get; set; }
    public virtual ApplicationRole Role { get; set; }
    public virtual Service Service { get; set; }

}

I can't understand how to do it in a correct way with data annotations or fluent api. I've tried both without any succes. It seems migration engine ignores any primary key changes of that model. At least when i add annotation or fluent api methods migration engine generates empty migration script.

i just added serviceId property and my table now looks like

CREATE TABLE [dbo].[AspNetUserRoles](
    [UserId] [nvarchar](128) NOT NULL,
    [RoleId] [nvarchar](128) NOT NULL,
    [ServiceId] [uniqueidentifier] NOT NULL,
 CONSTRAINT [PK_dbo.AspNetUserRoles] PRIMARY KEY CLUSTERED 
(
    [UserId] ASC,
    [RoleId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

and when i try to apply key changes via annotations or fluent api migration script looks like

public partial class rolesmigrate02 : DbMigration
{
    public override void Up()
    {
    }

    public override void Down()
    {
    }
}

fluent api:

modelBuilder.Entity<ApplicationUserRole>().HasKey(hk => new { hk.UserId, hk.RoleId, hk.ServiceId});

annotations

public partial class ApplicationUserRole : IdentityUserRole<string>
{
    [Key, Column(Order = 0)]
    public override string UserId { get; set; }
    [Key, Column(Order = 1)]
    public override string RoleId { get; set; }
    [Key, Column(Order = 2)]
    public Guid ServiceId { get; set; }

    public virtual ApplicationUser User { get; set; }
    public virtual ApplicationRole Role { get; set; }
    public virtual Service Service { get; set; }
}

i can do changes manualy in a db but i doubt
where is my mistake? why i can't extend this model by code first migration?

Upvotes: 2

Views: 2226

Answers (1)

taburetkin
taburetkin

Reputation: 313

After spending some time i've found this post Sam about identity 2 on StackOverflow

The Key thing was in base.OnModelCreating(modelBuilder)

if we want to reapply or modify predefined identity 2 mappings we should do it AFTER base.OnModelCreating.

so fluent api should look like

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // usualy i put this line to the end of this method but it should be before
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<ApplicationUserRole>().HasKey(hk => new { hk.UserId, hk.RoleId, hk.ServiceId});
    }

Upvotes: 3

Related Questions