EF Core HasData() not being called inside OnModelCreating
Asked Answered
A

2

2

I am on an Intel chip Mac.

When I do dotnet run, I expected the table Player to be created, and the data to be seeded from ApplicationDbContext.cs. I see the table being created, but no data inserted.

My implementation is quite basic with an SQLite db, but not sure why it is not working?

Output:

enter image description here

Player.cs

namespace OneModel.Models
{
    public class Player
    {
        public int PlayerId { get; set; }
        public string PlayerName { get; set; }

        public Player()
        {
        }
    }
}

ApplicationDbContext.cs

using Microsoft.EntityFrameworkCore;
using OneModel.Models;

namespace OneModel.Data
{
    public class ApplicationDbContext : DbContext
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
        {
            
        }
        public DbSet<Player> Players { get; set; }

        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);

            builder.Entity<Player>().HasData(
                new
                {
                    PlayerId = 1,
                    PlayerName = "Edgar",
                }
            );
        }
    }
}

Program.cs

using Microsoft.EntityFrameworkCore;
using OneModel.Data;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlite(connectionString));

// Add services to the container.
builder.Services.AddControllersWithViews();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

using (var scope = app.Services.CreateScope()) {
var services = scope.ServiceProvider;
var context = services.GetRequiredService<ApplicationDbContext>();
context.Database.Migrate();
}

app.Run();
Anthelion answered 4/4, 2022 at 21:48 Comment(1)
Could you please try new{PlayerName = "Edgar"} instead of new{PlayerId = 1,PlayerName = "Edgar"} ?Natie
A
3

Anyway, I played around and was finally able to fix using these steps:

  1. Delete the existing app.db.
  2. Recreate a blank app.db file.
  3. Add the HasData into the context now.
  4. Re-migrate the Models using dotnet-ef migrations add CreateTables -o Data/Migrations
  5. dotnet run to seed again, and should work now.

I am not sure why the problem occurred in the first place. Perhaps my original setup was trying to seed from ApplicationDbContext.cs before the migration in Program.cs. The gist is that I should have put HasData before I ran my migration.

Anthelion answered 6/4, 2022 at 3:26 Comment(3)
.HasData is like any schema change. You have to turn it into a migration first.Saffren
@JeremyLakeman that was the answer for me! Just had to run Add-Migration SeedData and I got the data into my database. Thanks!Lefler
@JeremyLakeman This is the piece I was missing from every other answer I have found. Which makes sense now that I conceptually think about how this might have worked.Mesopotamia
R
0

The error is explained 2 lines above your arrow in your screenshot: 'PLAYERID INTEGER NOT NULL CONSTRAINT PK_PLAYERS PRIMARY KEY AUTOINCREMENT'

This means that the database is trying to set the ID but you are trying to inject it yourself. Remove the PlayerId=1 from your seed.

Also, add the [Key] attribute to the PlayerId field, I know that using {Id} is implicit and the same. But you might want to keep in control and use the key to make it more clear to yourself and others that this is the primary key.

Rhoades answered 5/4, 2022 at 20:8 Comment(4)
Thanks, I tried it but getting a "PK not specified" message. It does look like I am supposed to specify the PK with the HasData method though, as per docs hereAnthelion
You need to specify key values in .HasData, otherwise the model diff service that generates migrations wouldn't be able to tell them apart.Saffren
@Sean You are right, this is my bad. But that does mean the seeder class is run correctly and you should have data present in the database. Do you have a screenshot of your empty database or maybe you are accidently looking in the wrong area? Maybe you can show your migration, because the seed data should be in the migration file.Rhoades
@Rhoades I should have included my migration file, had I known that the insert will be there too. My issue is that I created the migration before I put HasData, whereas I should have done so after. I have updated my own answer accordingly. thanksAnthelion

© 2022 - 2024 — McMap. All rights reserved.