2

I am a bit dazzled; I am using dotnet core (2.1) EF with migrations. When I create the first migration just based upon the context, it all looks OK actually.

so I have a context like:

public class DataContext : IdentityDbContext<User, IdentityRole<Guid>, Guid>
{

    public virtual DbSet<Country> Countries { get; set; }
    public virtual DbSet<CountryUser> CountryUsers { get; set; }
    //..more stuff

    public DataContext(DbContextOptions options) : base(options)
    { }
}

so after creating the migrations it wants to add:

migrationBuilder.CreateTable(
            name: "AspNetRoles",
            columns: table => new
            {
                Id = table.Column<Guid>(nullable: false),
                Name = table.Column<string>(maxLength: 256, nullable:
                //etc. etc. Removed rest of migrations.

All good I thought.

Then i started to follow the following article; How to seed an Admin user in EF Core 2.1.0?

After setting the HasData and seeding the DB, created a new migration, it created a new migration where it wanted to drop the AspNetRoles table and creates as new table IdentityRole. I just deleted the DB and tried to do it again, and now it only wants to insert the data when seeding. But i cannot figure out what I changed and even better, why it wanted to drop and create different tables.

can somebody explain when it wants to create AspNetRoles and when it wants to create IdentityRoles (and along the other tables that goes with it).

Just to be sure; the context was always extending from

: IdentityDbContext<User, IdentityRole<Guid>, Guid>

and my User:

public class User : IdentityUser<Guid>
{
    public virtual ICollection<CountryUser> CountryUsers { get; set; }
}

thnx!!

Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
Roelant M
  • 1,581
  • 1
  • 13
  • 28

1 Answers1

5

As I understand, you are following the following approach:

modelBuilder.Entity<IdentityRole>().HasData(new IdentityRole { Name = "Admin", NormalizedName = "Admin".ToUpper() });

There are two problems with this code.

The first is the usage of modelBuilder.Entity<IdentityRole>(). This makes IdentityRole class to be treated by EF Core as an entity, hence the IdentityRoles table it tries to create. It's because IdentityRole class is different from what your model is using - IdentityRole<Guid>. Change it to modelBuilder.Entity<IdentityRole<Guid>>() (and also the new operator) and the problem will be solved.

The second problem is that HasData requires PK values to be specified, as explained in the Data Seeding section of the EF Core documentation:

The primary key value needs to be specified even if it's usually generated by the database. It will be used to detect data changes between migrations.

So additionally to changing the HasData generic type argument, you need to pre generate Guid to be used as Id for the new role (see Entity Framework Core Auto Generated guid for more details a the similar issue) and use something like this:

modelBuilder.Entity<IdentityRole<Guid>>().HasData(
    new IdentityRole<Guid>
    {
        Id = new Guid("pre generated value"),
        Name = "Admin",
        NormalizedName = "Admin".ToUpper()
    }
);
Ivan Stoev
  • 195,425
  • 15
  • 312
  • 343
  • indeed, i changed it to ` modelBuilder.Entity>().HasData(new IdentityRole`.. allthough i thought i did it somewhere before. But the fact that you point out that it then wants to create a new entity makes actually total sense. Perfect! thnx – Roelant M Nov 27 '18 at 11:55
  • @IvanStoev is it really good practice to seed Identity data like that? I was under the impression that you should always use the EF Identity Manages to do that because other fields may need to be filled in or the fields may change later breaking your code – Marie Nov 27 '18 at 20:34
  • @Marie All I can say is that this is the EF Core out of the box general data seeding support. Whether it should be used with Identity or not is unrelated to EF Core. The link from the OP contains non EF Core way of seeding (basically what you mentioned). But this question was about `HasData`, hence the answer. – Ivan Stoev Nov 27 '18 at 20:40
  • The link you posted touches on data that requires more logic to be seeded ("If your scenario includes any of the following it is recommended to use custom initialization logic described in the last section") I think that Identity data falls under that category so it would still be "EF Core out of the box." Also, it may or may not apply but [just because the question was about HasData doesn't mean you should ignore that it might not be the best solution.](https://meta.stackexchange.com/a/66378/326778) – Marie Nov 27 '18 at 20:50