I have an app and it has a database behind it. This app is deployed in multiple instances, where each instance has different version of code and database. By different version, I mean it might be slightly older version of code and database.
What I would like to do is:
Start using EF6 database migrations on the development version.
In correct order (dev->stage->prod), deploy to other instances the development version and update the database using EF6 database migrations.
Create new instance of app, using EF6 database migrations.
The question I am running into is this:
I understand that I can enable migrations on my development instance, then do Add-Migration Initial –IgnoreChanges and create incremental migrations for new database changes. As other environments will be updated, these changes will be applied (running Update-Database during deployment).
However, my question is, with this kind of setup, how to handle when I have to spin up a new instance of the app? I need a migration which would create all the tables. I know how to create this migration also: by pointing the connecting string to empty database and running Add-Migration. However, when I will deploy my code to existing instances and run Update-Database, EF will try to run this baseline migration and crash.
How to handle these two scenarios in a simple and automated way?
I guess I am imagining two types of migrations:
Update-Database -Baseline-And-Incremental
and
Update-Database -Incremental
Also, this will all be automated, so I dont want to run Update-Database and pass in the non-baseline migration names to run on existing database during deployment.
1st
In your DbContext constructor add
Database.SetInitializer(new CreateDatabaseIfNotExists<MPContext>()); //Create database if not existed
Database.SetInitializer(new MigrateDatabaseToLatestVersion<yourContext, Configuration>()); // uses the configuration for migrations for this DbContext
and your configuration class should look like this:
internal sealed class Configuration : DbMigrationsConfiguration<DBO.MPContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = true;
}
}
AutomaticMigrationsEnabled = true; // enables automatic migrations
AutomaticMigrationDataLossAllowed = true;
//this kinda gives permision to delete a table, what I mean is say you have a one to
//many relation in a table and you decide to remove it for any reason by adding this
//code you allow the migration to delete the reference (Sorry for the bad english)
public class TEST{
public List<TEST2> test2 {get;set;}
}
if you decide to remove test from test it deletes the reference from TEST class (thereore you lose that data)
P.S if you are using an online DB you might need to add Persist Security Info=True to your connection string
Hope this helps
I have an MVC web application with code-first Entity Framework. We install this application in various computers as a local application. I made a migration to upgrade the database (in this case I added a new table), and after running the migration on upgrade, I want to insert initial data to the database so the users will be able to add/edit/delete them but I don't want the table to be empty at the first time.
Is there a way to do it automatically on upgrade without running a SQL script manually?
Migration class has up method,you can override it and insert/update records using SQL :
public override void Up() {
AddColumn("dbo.Posts", "Abstract", c => c.String());
Sql("UPDATE dbo.Posts SET Abstract = LEFT(Content, 100) WHERE Abstract IS NULL");
}
(Source)
Yes there is. You essentially write a class to conditionally check and insert values, and then you link this class to your entity framework database initialiser. It runs each time there is a migration to be performed, but I think you can change exactly when it runs (e.g. Application startup).
This link will give you the rough idea:
Entity Framework Inserting Initial Data On Rebuild
I have an exact code sample on my PC but I won't be on it until tomorrow. If this link doesn't quite do what you want, I can send you some code tomorrow which definitely will.
Given Scenratio:
We've built a web application using Asp.net MVC and Entity Framework Code First, which builds a database dynamically for each customer.
Given a connection string (connectionStr) and a certain Configuration, We've made Add Migrations [Name] in order to create an empty migration, which has an empty Up function. We did that on purpose.
We don't wanna use automatic migrations here - we want full control, so we have a program making the migrations using a DbMigrator Class.
Our goal is to run a manual Seed inside this Up function.
This is some of the code incharge of making the migration, which indeed works perfectly:
Dim myConfiguration As New SomeNamespace.Migrations.Config1.Configuration
myConfiguration.TargetDatabase = New Infrastructure.DbConnectionInfo(connectionStr, "System.Data.SqlClient")
Dim dbMig As New Entity.Migrations.DbMigrator(myConfiguration)
If dbMig.GetPendingMigrations.Count > 0 Then
dbMig.Update() ' This makes the Up function work - the problem is inside it.
End If
Problem:
The problem is that when the Up function of the Migration is run, we cannot get the database context. We need it in order to make a Seed.
We hope that there's a way to get the Configuration object (myConfiguration) used to initiate the DbMigration (dbMig) instance, or some other way, so we can get the database context (maybe getting the ConnectionString somehow).
Help getting access to one of configuration object / database context / ConnectionString - would be very appreciated.
I don't think so, because what Up method does is filling Operations collection, and DbMigrator class actually executes these operations. So there is no 'context' when up is called.
What you can do is get connection string via ConfigurationManager class directly
I'm trying to use EF 4.3 migrations with multiple code-first DbContexts. My application is separated into several plugins, which possibly have their own DbContext regarding their domain. The application should use one single sql-database.
When I try to auto migrate the contexts in an empty database, this is only successful for the first context. Every other context needs the AutomaticMigrationDataLossAllowed-Property set to true but then tries to drop the tables of the previous one.
So my question is:
How can I tell the migration-configuration just to look after the tables defined in their corresponding context and leave all others alone?
What is the right workflow to deal with multiple DbContexts with auto-migration in a single database?
Thank you!
Here is what you can do. very simple.
You can create Configration Class for each of your context.
e.g
internal sealed class Configuration1 : DbMigrationsConfiguration<Context1>{
public Configuration1 (){
AutomaticMigrationsEnabled = false;
MigrationsNamespace = "YourProject.Models.ContextNamespace1";
}
}
internal sealed class Configuration2 : DbMigrationsConfiguration<Context2>{
public Configuration2 (){
AutomaticMigrationsEnabled = false;
MigrationsNamespace = "YourProject.Models.ContextNamespace2";
}
}
Now you add migration. You dont need to enable migration since you already did with the 2 classed above.
Add-Migration -configuration Configuration1 Context1Init
This will create migration script for context1. your can repeat this again for other Contexts.
Add-Migration -configuration Configuration2 Context2Init
To Update your database
Update-Database -configuration Configuration1
Update-Database -configuration Configuration2
This can be done in any order. Except you need to make sure each configration is called in sequence.
Code First Migrations assumes that there is only one migrations configuration per database (and one context per configuration).
I can think of two possible solutions:
Create an aggregate context that includes all the entities of each context and reference this "super" context from your migrations configuration class. This way all the tables will be created in the user's database, but data will only be in the ones that they've installed plugins for.
Use separate databases for each context. If you have shared entities between the contexts, add a custom migration and replace the CreateTable(...) call with a Sql("CREATE VIEW ...") call to get the data from the entity's "originating" database.
I would try #1 since it keeps everything in a single database. You could create a seperate project in your solution to contain your migrations and this "super" context. Just add the project, reference all of your plugins' projects, create a context that includes all of the entities, then call Enable-Migrations on this new project. Things should work as expected after that.
I have a working site with multiple contexts using migrations. However, you do need to use a separate database per context, and it's all driven off of a *Configuration class in the Migrations namespace of your project, so for example CompanyDbContext points to Company.sdf using CompanyConfiguration. update-database -configurationtypename CompanyConfiguration. Another LogDbContext points to Log.sdf using LogConfiguration, etc.
Given this works, have you tried creating 2 contexts pointing at the same database and telling the modelbuilder to ignore the other context's list of tables?
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Ignore<OtherContextsClass>();
// more of these
}
Since the migrations work with the ModelBuilder, this might do the job.
The crappy alternative is to avoid using Automatic Migrations, generate a migration each time and then manually sift through and remove unwanted statements, then run them, although there's nothing stopping you from creating a simple tool that looks at the Contexts and generated statements and does the migration fixups for you.
Ok, I have been struggling with this for a day now, and here is solution for those seeking the answer...
I am assuming that most people reading this post are here because they have a large DbContext class with a lot of DbSet<> properties and it takes a long time to load. You probably thought to yourself, gee, that makes sense, I should split up the context, since I won't be using all of the dbsets at once, and I will only load a "Partial" context based on the situation where I need it. So you split them up, only to find out that Code First migrations don't support your way of revolutionary thinking.
So your first step must have been splitting up the contexts, then you added the MigrationConfiguration class for each of the new contexts, you added the connection strings named exactly the same as your new Context classes.
Then you tried running the newly split up contexts one by one, by doing Add-Migration Context1 then doing Update-Database -Verbose...
Everything seemed to work fine, but then you notice that every subsequent Migration deleted all tables from the Previous migration, and only left the tables in from the very last migration.
This is because, the current Migrations model expects Single DbContext per Database, and it has to be a mirror match.
What I also tried, and someone suggested here doing that, is create a single SuperContext, which has All the Db sets in it. Create a single Migration Configuration class and run that in. Leave your partial Context classes in place, and try to Instantiate and use them. The EF complains that the Backing model has changed. Again, this is because the EF compares your partial dbcontext to the All-Sets context signature that was left over from your Super Context migration.
This is a major flaw in my opinion.
In my case, I decided that PERFORMANCE is more important than migrations. So, what I ended up doing, is after I ran in the Super context and had all the tables in place, I went into the database and Manually deleted _MigrationHistory table.
Now, I can instantiate and use my Partial Contexts without EF complaining about it. It doesn't find the MigrationHistory table and just moves on, allowing me to have a "Partial" view of the database.
The trade off of course is that any changes to the model will have to be manually propagated to the database, so be careful.
It worked for me though.
As mentioned above by Brice, the most practical solution is to have 1 super DbContext per application/database.
Having to use only 1 DbContext for an entire application seems to be a crucial technical and methodological disadvantage, cause it affects Modularity among other things. Also, if you are using WCF Data Services, you can only use 1 DataService per application since a DataService can map to only 1 DbContext. So this alters the architecture considerably.
On the plus side, a minor advantage is that all database-related migration code is centralized.
I just came across this problem and realised the reason I had split them into different contexts was purely to have grouping of related models in manageable chunks and not for any other technical reason. Instead I have declared my context as a partial class and now different code files with different models in them can add DbSets to the DbContext.
This way the automigration magic still works.
I've got it working with manual migrations, but you can't downgrade as it can't discrimitate between configurations in the __MigrationHistory table. If I try and downgrade then it treats the migrations from the other configurations as automatic and since I don't allow data loss it fails. We will only ever be using it to upgrade though so it works for our purposes.
It does seem like quite a bit ommision though, I'm sure it wouldn't be hard to support it provided there was no overlap between DbContexts.
Surely the solution should be a modification by the EntityFramework team to change the API to support the direct modification of the _MigrationHistory table to a table name of your choice like _MigrationHistory_Context1 such that it can handle the modification of independent DbContext entities. That way they're all treated separately, and its up to the developer to ensure that the names of entities don't collide.
Seems like there are a lot of people who share my opinion that a duplicate DbContext with references to the superset of entities is a bogus non-enterprise friendly way to go about things. Duplicate DbContexts fail miserably for modular (Prism or similar) based solutions.
I want people to know that the answer with this below is what worked for me but with one caveat: don't use the MigrationsNamespace line.
internal sealed class Configuration1 : DbMigrationsConfiguration<Context1>{
public Configuration1 (){
AutomaticMigrationsEnabled = false;
MigrationsNamespace = "YourProject.Models.ContextNamespace1";
}
}
internal sealed class Configuration2 : DbMigrationsConfiguration<Context2>{
public Configuration2 (){
AutomaticMigrationsEnabled = false;
MigrationsNamespace = "YourProject.Models.ContextNamespace2";
}
}
However, I already had the 2 databases established with their own contexts defined so I found myself getting an error saying "YourProject.Models namespace already has ContextNamespace1 defined". This was because the "MigrationsNamespace = "YourProject.Models.ContextNamespace2";" was causing the dbcontext to be defined under the YourProjects.Models namespace twice after I tried the Init (once in the migration Context1Init file and once where I had it defined before).
So, I found that what I had to do at that point was start my database and migrations from scratch (thankfully I did not have data I needed to keep) via following the directions here:
http://pawel.sawicz.eu/entity-framework-reseting-migrations/
Then I changed the code to NOT include the MigrationsNamespace line.
internal sealed class Configuration1 : DbMigrationsConfiguration<Context1>{
public Configuration1 (){
AutomaticMigrationsEnabled = false;
}
}
internal sealed class Configuration2 : DbMigrationsConfiguration<Context2>{
public Configuration2 (){
AutomaticMigrationsEnabled = false;
}
}
Then I ran the Add-Migration -configuration Configuration1 Context1Init command again and the Update-Database -configuration Configuration1 line again (for my 2nd context too), and finally, everything seems to be working great now.
My application is using EF code-first design and all generally works very well.
Via a private configuration file, I can specify how I would like EF to handle changes to the db schema, and so create/recreate the relevant tables as desired - the options are "never" "create", "always", "onSchemaChanged" and (for the future) "onSchemaModified".
This works well - but I am getting lost in a couple of places .....
During development, I would like to use the hook as described in
"Database in use error with Entity Framework 4 Code First" - but this seems to execute on EVERY run of my program"
public void InitializeDatabase(Context context)
{
context.Database.SqlCommand("ALTER DATABASE Tocrates SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
_initializer.InitializeDatabase(context); // Maybe this does nothing if not needed
context.Database.SqlCommand("ALTER DATABASE Tocrates SET MULTI_USER")
}
So .. to real my question: Is there an override that I can use to detect whether EF will ACTUALLY be trying to modify the database, so I can set this SINGLE_USER stuff when needed? And if so, can I detect the reason EF it is doing so (see my list of options above) so I can log the reason for change?...
All help and suggestions are very much appreciated.
Unless you have set the database intializer to null initializers run always once (per application lifetime) when you are using a context for the first time. What then actually happens depends on the initializer (your inner _intializer):
For DropCreateDatabaseAlways and CreateDatabaseIfNotExists it's clear by their name what they do.
For DropCreateDatabaseIfModelChanges there is only the question if the model changed or not. EF detects this by comparing a model hash with a hash stored in the database. You can check this yourself by calling...
bool compatible = context.Database.CompatibleWithModel(true);
...within your custom InitializeDatabase and then decide based on the result if you want to send your SqlCommands or not. (Don't call this with a self-created context because it will cause the database to be intialized first before the model compatibilty is checked.) The parameter bool throwIfNoMetadata (which is true in my example) causes EF to throw an exception if the model hash in the database does not exist. Otherwise the method will return true in that case.
For a custom inner initializer: Whatever your code will do.