EF Core’s Migration / Seeder gotchas
Especially in dotnet core 3.0
1. Computed Columns do not work with Sqlite
It used to be that EF Core would ignore computed columns, but in dotnet core 3.0, I have to conditionally add my computed columns to the model builder.
if (!Database.IsSqlite())
{
builder.Entity<Person>()
.Property(bl => bl.Age)
.HasComputedColumnSql(...);
}
2. Use Database.EnsureCreatedAsync(…) for MsSQL and Sqlite
For performing a DB Migration at runtime, I used to think EnsureCreated(…)
and its async EnsureCreatedAsync(…)
counterpart would only create the database if it does not exist. However, it will actually perform a migration, if the database did not previously exist, and do absolutely nothing if the DB exists already.
I also noticed it does not work well with MySql via Pomelo, which prefers the more descriptive Database.MigrateAsync(…)
.
if (!DbTypes.IsInMemory() && !_environment.IsTest()) {
if (DbTypes.IsSqlServer()) {
await _context.Database.EnsureCreatedAsync();
await _context.Database.MigrateAsync();
}
else if (DbTypes.IsSqlite()) {
await _context.Database.EnsureCreatedAsync();
}
else await _context.Database.MigrateAsync();
}
DbTypes
is a custom class (sorry), but you might have noticed that the migrations do not run, if the DB is an InMemory DB, or the execution is in a test environment.That brings us to:
3. Skip EnsureCreated() and Migrate() when using InMemory DBs
When performing a DB Migration at runtime, there’s really no point doing so with an InMemory DB. You should just skip it instead. However, instead of gracefully skipping it, EF Core will fail with an Exception if you attempt to.