Hi,
Where is the right place to call Database.Migrate post model configuration?
I tried calling it in the OnConfiguring method but an InvalidOperationException is thrown, saying:
An attempt was made to use the context while it is being configured. A DbContext instance cannot be used inside OnConfiguring since it is still being configured at this point. This can happen if a second operation is started on this context before a previous operation completed. Any instance members are not guaranteed to be thread safe.
I'm working on a multi-tenant project where each tenant has a dedicated DB and connection string (provided dynamically by an external DI-provided service from an external DB).
Here's what my DbContext looks like:
```c#
public class AppDbContext : IdentityDbContext
{
readonly IAppConnectionStringProvider _ConnStringProvider;
public AppDbContext(DbContextOptions
{
}
public AppDbContext(DbContextOptions
IAppConnectionStringProvider connStringProvider) : this(options)
{
_ConnStringProvider = connStringProvider;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
//TODO might be redundant
if (optionsBuilder.IsConfigured)
return;
optionsBuilder.UseSqlServer(_ConnStringProvider.ConnectionString);
Database.Migrate();
}
}
```
What IAppConnectionStringProvider does, is it retrieves the tenant data and its connection string using a different CatalogDbContext that maintains the tenant data.
In reference to @bricelam's comment, I'm requesting guidance on where to call Database.Migrate.
EF Core version: 2.2.0
Database Provider: Microsoft.EntityFrameworkCore.SqlServer
It should go in your application startup logic.
@smitpatel
At the startup stage, the connection string isn't known yet. The connection string is retrieved from a different DB with a different DbContext, using an injected service.
I've updated my original post, was indeed not clear enough.
@bricelam may have better idea.
I put following in Configure method inside startup.cs and it initialized the database before running the app. You can achieve similar by putting in Program.Main method too.
C#
using (var scope = app.ApplicationServices.CreateScope())
{
using (var db = scope.ServiceProvider.GetService<ApplicationDbContext>())
{
db.Database.Migrate();
}
}
Program.Main() is a better place than Startup.Configure(). BUT we discourage using Migrate() at all during startup. It's typically part of deployment, not startup. Creating an admin page to create/update the database after deployment is another good option.
Be careful with database permissions. Most users SHOULDN'T be able to drop tables, etc.
@smitpatel
Either Main or Startup won't work for me, because the Tenant is not known yet, and additionally, there may be new tenants added.
@bricelam
Creating an admin page to create/update the database after deployment is another good option.
Sounds like what I'm gonna do. Gonna migrate/generate the tenant DBs on demand, as they're created by admin.
Thank you both!
Most helpful comment
Program.Main() is a better place than Startup.Configure(). BUT we discourage using Migrate() at all during startup. It's typically part of deployment, not startup. Creating an admin page to create/update the database after deployment is another good option.
Be careful with database permissions. Most users SHOULDN'T be able to drop tables, etc.