I am trying to create a migration, that would purge data for the whole schema and then run migrations.
I have found a way to run the migrations for the context set only.
I cannot find a way to delete the data in the given context, and not in the whole database.
Current code for migrations only:
var context = scope.ServiceProvider.GetRequiredService<TContext>();
await context.Database.MigrateAsync();
context.Database.EnsureDeleted(); has allowed me to delete the database before running migrations, but it seems to ignore the context I provide (as it says in the documentation).
Any ideas on how to delete data in the context?
Thanks!
What I would suggest is to create an empty migration, then add the raw SQL in order to drop the schema:
public partial class DropSchemaMigration : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("DROP SCHEMA MY_SCHEMA;");
}
}
Then do your other migrations. Assuming that this is a code-first approach.
You can stash all your changes, do the empty migration, pop stash and generate other migrations.
Or, if it feels more natural, do your migration, and on the first line in the Up method you can set the SQL command
public partial class MyMigration: Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("DROP SCHEMA MY_SCHEMA;");
//auto-generated mappings
}
}
Related
I'm trying to seed identity roles and users. I have the following:
public class AppDbContext : IdentityDbContext<User, Role, int>
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<Role>().HasData(new Role
{
Id = 1,
Name = "SystemAdmin",
NormalizedName = "SYSTEMADMIN"
});
base.OnModelCreating(builder);
}
}
This creates the role in the DB as expected, however the NormalizedName is left null, regardless of whether I specify a value or not. The same thing happens when trying to create a user with normalized properties.
How do I go about seeding identity data (roles, users) with normalized data in the relevant properties?
Worth noting I'm using:
Microsoft.AspNetCore.Identity.EntityFrameworkCore v6.0.8
Microsoft.EntityFrameworkCore v6.0.8
This was my mistake... I had created the first migration without specifying the NormalizedName value, then given it a value but not created a new migration to apply this change. So when I ran dotnet ef migrate script, it showed me the script for the first migration, and when I ran dotnet ef database update, it updated the database to apply only the first migration.
So the obvious fix to this was to create a new migration:
dotnet ef migrations add NormalizedSeedData
Then update the database with the latest migration:
dotnet ef database update
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
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