I have an issue attempting to use Migrations in a ASP.NET Core solution using EF Core where there are multiple DbContext that share the same SQL database.
In my application startup method I'm getting a reference to each context and calling the context.Database.Migrate() method. However as both of these contexts are pointing to the same underlying database I'm getting the error:
There is already an object named '__EFMigrationsHistory' in the database.
Here's a MCVE:
class DbContextA : DbContext {}
class DbContextB : DbContext {}
static void Main(string[] args)
{
var contextA = GetContextFromDIContainer<DbContextA>();
var contextB = GetContextFromDIContainer<DbContextB>();
contextA.Database.Migrate();
contextB.Database.Migrate();
}
void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DbContextA>(opt =>
{
opt.UseSqlServer("connectionstring");
});
services.AddDbContext<DbContextB>(opt =>
{
opt.UseSqlServer("connectionstring");
});
}
Note that each DbContext exists in a separate assembly in which the Migrations are configured.
I am able to manually execute the respective migrations with the Update-Database CLI tool but it doesn't seem to work as part of my app startup code.
Is there a way to execute migrations on both contexts at runtime and bypass the __EFMigrationsHistory table creation if already exists?
I think your problem is just two Context try to use same migration history table
try specific your migration history table for each
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseSqlServer(
connectionString,
x => x.MigrationsHistoryTable("__MyMigrationsHistoryForDBContextA", "mySchema"));
it should be fix
Custom Migrations History Table
Related
Originally I was using IdentityDbContext for awhile. Everything was working and I was doing migrations and such. But recently I decided to let AWS Cognito handle the users and password thus no longer needing IdentityDbContext. So I switched my ApplicationDbContext class to inherit DbContext instead.
I cleared the migrations and snapshots, killed and pruned the docker containers. Once I try to do the initial migration I get these errors in the Package Manager Console:
An error occurred while accessing the Microsoft.Extensions.Hosting services.
Continuing without the application service provider.
Error: Object reference not set to an instance of an object.
Unable to create an object of type 'ApplicationDbContext'.
For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
After doing some research I added a class that inherits the IDesignTimeDbContextFactory and I was actually able to add migrations but the first error still remained:
An error occurred while accessing the Microsoft.Extensions.Hosting services.
Continuing without the application service provider.
Error: Object reference not set to an instance of an object.
My project structure is setup so the Startup file is in a different project than where the ApplicationDbContext Class is but it's containerized by docker-compose.
Project.Api
- Startup.cs
- Program.cs
Project.App
- ApplicationDbContext.cs
- Migrations Folder
Here is how I added the database in Startup.cs:
var connectionString = Configuration.GetSection("ConnectionStrings").GetSection("DefaultConnection").Value;
services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseNpgsql(connectionString,
b =>
{
b.MigrationsAssembly("Project.App");
});
});
What the ApplicationDbContext.cs looks like:
public ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options){}
// DbSet<Entities>...
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// ...
// ...
}
}
public class ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
{
private readonly DbConfig _dbConfig;
public ApplicationDbContextFactory(IOptionsMonitor<DbConfig> dbConfig)
{
_dbConfig = dbConfig.CurrentValue;
}
public ApplicationDbContext CreateDbContext(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
optionsBuilder.UseNpgsql(_dbConfig.DefaultConnection);
return new ApplicationDbContext(optionsBuilder.Options);
}
}
When I run the migration command I select the Default project as Project.App, and in the Package Manager Console I write:
Add-Migration initMigration -Context ApplicationDbContext -Project Project.App -StartupProject Project.Api.
As mentioned before, with the DbContextFactory included, it just shows this error:
An error occurred while accessing the Microsoft.Extensions.Hosting services.
Continuing without the application service provider.
Error: Object reference not set to an instance of an object.
Ended up being an AWS configuration in the Program.cs file where I wasn't passing my AWS profile to the AWSOptions class.
I need to create a database in ASP.NET Core and use identity, and I need to use UseInMemoryDatabase but when I try to add a migration, I get this error:
Unable to create an object of type 'DortajContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
This is my start up:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContextPool<DortajContext>(options => options.UseInMemoryDatabase(databaseName: "DortajDistance"));
services.AddIdentity<IdentityUser, IdentityRole>().AddEntityFrameworkStores<DortajContext>();
services.AddControllers();
}
and this is my context :
public class DortajContext : IdentityDbContext<User, Role, int>
{
public DortajContext(DbContextOptions<DortajContext> options)
: base(options)
{
}
public DbSet<UserDistanceHistory> UserDistanceHistories { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.ApplyConfigurationsFromAssembly(typeof(IType).Assembly);
}
}
How can I solve this problem?
Why do you need migrations for in-memory database?
Migrations are used to versioning database. It is useful when you have a database in production, you changed smth and you can update it with migrations. There is no need to use it for in-memory databases. You can read more about migrations here.
Anyway, InMemory provider was designed only for unit and integration testing. If you want to use in-memory in developing and production, you should use SQLite. Here is issue oh the github
I have two WebApp.
Both refer to the same database, and the need to organize the migration of both App.
Both application setup to MigrateDatabaseToLatestVersion.
When you start with a blank database application first comes the creation of scheme, in table __MigrationHistory create record about this, and everything is OK.
But when you start the second application should make changes to existing database tables, but the application crashes with an error - "... This table already exists"
How to solve this problem?
Example of code second app
Global.asax
Database.SetInitializer(new SyncContextInitializer());
using (var context = new SyncDataContext())
{
context.Database.Initialize(force: true);
}
public class SyncContextInitializer : MigrateDatabaseToLatestVersion<SyncDataContext, SyncConfiguration>
{ }
public class SyncDataContext : DataContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new IdentityUserLoginMap());
.......
base.OnModelCreating(modelBuilder);
}
}
public sealed class SyncConfiguration : DbMigrationsConfiguration<SyncDataContext>
{
private readonly bool _pendingMigrations;
public SyncConfiguration()
{
AutomaticMigrationDataLossAllowed = true;
AutomaticMigrationsEnabled = true;
var migrator = new DbMigrator(this);
_pendingMigrations = migrator.GetDatabaseMigrations().Any();
}
......
.....
}
That's not going to work. When you modify the model in one app, it looks at the prior migration (in code) to compare. It will try to recreate the changes made in the other app or you will get a model mismatch error.
The best solution is to maintain the models in one application. Otherwise you would have to create a migration in the other application to keep it in sync:
// Application 1:
add-migration MyChanges
update-database
// Application 2:
add-migration SyncMyChanges -IgnoreChanges // Just update meta model
update-database
You would need to take care that there were no pending changes in App 2. See Entity Framework Under the Hood
If the models are not shared, you may just need to create an initial migration starting point in both apps:
add-migration Initial -IgnoreChanges
I currently have an asp.net MVC 4 application which contains Entity framework 6 Code First models, DbContext and Migrations. In an attempt to separate this from my web application so I can re-use these database classes in another project I have moved all related Entity Framework classes to their own project.
However now when I run the solution it thinks my model has changed and attempts to run all my migrations once more. The problem appears to be in my use of SetInitializer as if I comment out this line I can run the web application as per normal.
public static class DatabaseConfig
{
public static void Initialize()
{
System.Data.Entity.Database.SetInitializer(new MigrateDatabaseToLatestVersion<G5DataContext, Configuration>());
// make sure the database is created before SimpleMembership is initialised
using (var db = new G5DataContext())
db.Database.Initialize(true);
}
}
This wasn't a problem until I've tried to move all the Entity Framework classes. Is this not possible, or have I done something fundamentally wrong?
At startup, EF6 queries exiting migrations in your database, as stored in the __MigrationHistory table. Part of this table is a context key, which includes the namespace of the entities.
If you move everything to a new namespace, EF6 doesn't recognize any of the previously run migrations, and tries to rebuild the database.
A quick solution is to run a script to rename the context key in the __MigrationHistory table to your new namespace. From http://jameschambers.com/2014/02/changing-the-namespace-with-entity-framework-6-0-code-first-databases/ :
UPDATE [dbo].[__MigrationHistory]
SET [ContextKey] = 'New_Namespace.Migrations.Configuration'
WHERE [ContextKey] = 'Old_Namespace.Migrations.Configuration'
Would also like to add that you should remember to change the ContextKey property in your Configuration class. I did the above but it was still trying to create a new database. Here's an example:
Before:
internal sealed class Configuration : DbMigrationsConfiguration<PricedNotesContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
ContextKey = "Synapse.DAL.PricedNotesContext";
}
protected override void Seed(PricedNotesContext context)
{
}
}
After:
internal sealed class Configuration : DbMigrationsConfiguration<PricedNotesContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
ContextKey = "SynapseDomain.DAL.PricedNotesContext";
}
protected override void Seed(PricedNotesContext context)
{
}
}
Hope this helps anyone who is stuck on this. It's a shame that it shouldn't be easier...
I am trying to setup automatic migration updates using the IdentityDbContext class and propagating changes to the actual DbContext for the entire database.
Before I get into the code, on my implementation of the IdentityDbContext with automatic migrations I get this error:
Automatic migrations that affect the location of the migrations history system table (such as default schema changes) are not
supported. Please use code-based migrations for operations that affect
the location of the migrations history system table.
I am not going to post the models that are associated with the migrations and context code unless someone finds them of use.
Implemenation of the IdentityDbContext:
public class SecurityContext: IdentityDbContext<User>
{
public SecurityContext() : base("MyActualContext")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//removing this line I do not get an error, but everything gets placed into the dbo schema. Keeping this line, i get the above error.
modelBuilder.HasDefaultSchema("ft");
}
}
So I tried adding this class to place the migrations history into the correct schema. This, in fact, does move the migrations history into the correct schema, but everything else remains in the dbo schema.
public class MyHistoryContext : HistoryContext
{
public MyHistoryContext(DbConnection dbConnection, string defaultSchema)
: base(dbConnection, defaultSchema)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.HasDefaultSchema("ft");
}
}
public class SecurityContextMigrations : DbMigrationsConfiguration<SecurityContext>
{
public SecurityContextMigrations()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = true;
//When the migrations get set, I use the new class created to move the migrations to the correct schema.
SetHistoryContextFactory("System.Data.SqlClient", (c, s) => new MyHistoryContext(c, s));
}
protected override void Seed(SecurityContext context)
{
...
}
}
Ideally, I'd like everything to be in the ft schema. I don't think the migrations are that complex that I need to manually setup the migrations. I was hoping for simplicity sake, I could use automatic migrations for this. I am wondering if this approach is impossible and what I need to do to make this happen and any changes made to the models do get propagated.
I have a similar issue with Oracle 12c and EF6: I cannot get automatic migrations to work. I found, however, the following partial success factors: - I needed to set
modelBuilder.HasDefaultSchema("")
on my DbContext in order to get the runtime see the tables in the logon schema of the particular user - For the update-database it was necessary to set the MyHistoryContext parameters like that:
public class MyHistoryContext : HistoryContext
{
public MyHistoryContext(DbConnection dbConnection, string defaultSchema)
: base(dbConnection, defaultSchema)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.HasDefaultSchema("L2SRVRIZ");
}
}
NOTE: You need to hard-code the schema name there. In this way, update-database does not try to use dbo as schema (but still no automatic migrations are possible, they will drop your MigrationHistory table and mess up everything). This is in my opinion a nasty bug inside either EF6 or the Oracle custom class. As I have no maintenance contract with them, I cannot file a ticket.
For your case, I think its not possible somehow by design to avoid the error message with automatic migrations. EF6 thinks, for some reason, that if you use a custom schema name, that you actually moving the __MigrationHistory table from the default dbo schema, which is of course not true.
Or, did you find a solution for that?
BR Florian