I watched a screencast from MSDN BLOG that talks about database migration.
Is there anyone who knows when can we use this feature? It looks it doesn't work in CTP5 yet.
By the way, is there any way to seed the initial data after I changed the schema code?
This is what am I doing right now, it wipes all the data every time I altered the model.
DbDatabase.SetInitializer<Context>(
new DropCreateDatabaseIfModelChanges<Context>());
They most likely get this migration feature in the RTM version which is targeted for the first quarter of 2011.
To populate database with some initial data you can create your own database initializer and have it inherit from your desired strategy (right now we have 2 options) and then override Seed method inside it:
public class MyInitializer : DropCreateDatabaseIfModelChanges<MyContext>
{
protected override void Seed(InheritanceMappingContext context)
{
MyEntity entity = new MyEntity()
{
...
};
context.MyEntities.Add(entity);
context.SaveChanges();
}
}
Alpha 3 is out now.
http://blogs.msdn.com/b/adonet/archive/2011/09/21/code-first-migrations-alpha-3-no-magic-walkthrough.aspx
EF 4.1 Candidate Release has been issued in March and looks like this Migration feature is not yet included
Related
This question already has answers here:
How to seed in Entity Framework Core 2?
(9 answers)
Closed 4 years ago.
I have a migration class:
public partial class TestMigration : Migration
{
protected override void Up(MigrationBuilder db)
{
At the end of the Up method, I would like to add some data (seed). MigrationBuilder exposes some methods, also Sql(), but I would like to use EF.
Can I inject DbContext here and do some stuff?
I do not recommended you to seed the database in the Migration up or down. this is a bad practice.
You can execute Sql statement in your up/down method and seed the tables as following:
EF6:
public override void Up()
{
Sql("INSERT INTO Customers (CustomerName, ContactName) VALUES ('Cardinal','Tom B.')");
...
}
EF Core 1.0 /7:
protected override void Up(MigrationBuilder db)
{
db.Sql("INSERT INTO Customers (CustomerName, ContactName) VALUES ('Cardinal','Tom B.')");
}
where Customer is an entity of the DbSet<'Customer'> Customers by your DbContext
You can create you DbContext during the migration by suppling the connection string or load it from the confiugration but think good about that the database at this time point is not completed and the updating progress still in use. this thing might make for you later really a big troubles.
1) Use the normal DBInitializer.Seed to seed the data to the database.
2) Use the Sql statements in your Migrations Up/Down to transform(update/delete/insert) the data and make the data compatibility between the old database schema and the new one during the migration.
3) Do not try to create DbContext wthing the migration process.
It’s not possible to modify the data during migrations. The current solution for seeding databases is to do that when the application launches, as shown in the Unicode Store sample which ensures that all seed data is available.
There was a discussions on this in issue 3042, the current effort seems to be to change the migration story to make it possible to seed data during a migration. It’s currently planned post-RTM though, so I wouldn’t bet on that for now.
I'm using Entity Framework 6 with this DbMigrationsConfiguration:
public sealed class Configuration : DbMigrationsConfiguration<DataContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
}
protected override void Seed(Danfoss.EnergyEfficiency.Data.DataContext context)
{
//Adding initial data to context
context.SaveChanges();
}
}
I'm using it in WebAPI in this way:
public static void Register(HttpConfiguration config)
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<DataContext, Configuration>());
}
I have noticed that Seed function is running every time my application start up. How can I prevent this? I only like it to run the first time it runs, when it build the initial tables.
The DbMigrationsConfiguration.Seed method is called every time you call Update-Database. The reasoning behind that is explained in this blog by One Unicorn.
That means that you have to write your Seed code to cope with existing data. If you don't like that, you can vote for a change on CodePlex.
In the meantime, to quote the blog:
The best way to handle this is usually to not use AddOrUpdate for
every entity, but to instead be more intentional about checking the
database for existing data using any mechanisms that are appropriate.
For example, Seed might check whether or not one representative entity
exists and then branch on that result to either update everything or
insert everything
Another option, that I have used in the past, is to add standing data that is related to a migration in the migration itself, using the Sql command. That way it only runs once. I have tended to move away from this because I prefer to keep the seeding in one place.
I've had the same issue in that I wanted an initial user created on database build. What I did was to create a blank migration and then add in the user creation there. Since a migration technically runs only once unless you remove and reapply migrations, this would ensure it would only run once on database creation.
I know that this question is a bit old, so it may help others or you may not be using migrations. But if you are, this is a handy technique.
Im unable to scaffold a controller (MVC5 Controller with views, using Entity Framework) in Visual studio 2013 (update 3 and 4). The error message is below:
There was an error running the selected code generator:
A configuration for type 'Library.Morthwind.Models.Catgeory' has already been added. To reference the existing configuration use the Entity<T>() or ComplexType<T>() methods
I have created the models by selecting 'Reverse Engineer Code First' from the 'Entity Framework Power Tools Beta 4' Tool menu.
Any ideas about what might cause this error?
I had the same issue today.
I had added some custom configuration for one of my Model classes to add a relationship using the fluent API. This was specified in my dbContext class in the OnModelCreating override using the following:
modelBuilder.Configurations.Add(new OrderConfiguration());
Commenting out the above line allowed the Controller scaffolding to run as expected.
VS 2013 update 2 had a problem with this and the scaffolding came up with an unhelpful error with no further information. In installed Update 3 and it gave just enough detail to track down the underlying issue.
Jeff.
I've been having this issue too. Jeff's solution works in some cases. But as my DbContext grew with more models that had keys needing to be mapped I couldn't delete the Configurations.Add() methods because I would then get errors that EF couldn't find primary keys, etc...
I did discover that by changing my DBContext derived class to use IDbSet properties instead of DbSet I could generate the controllers and views just fine. However, for me this introduced another issue, IDbSet does not support the async methods.
It appears I can either generate non-async controllers with configurations in place or async methods without configuration classes.
If your context properties are of type DbSet, try changing them to IDbSet. If you aren't generating async controller methods this may work for you.
I also had the same issue and changing my context class to use IDbSet allowed me to successfully use the scaffolding to create a new controller. But since I didn't want to give up the async methods I changed the context back to use DbSet and that worked for me.
Here is how I resolved this issue.
I have Visual Studio 2013 Update 4.
I use EF Power Tools.
Comment out all of the DbSet < ... >
Inside OnModelCreating, only leave the object you are scaffolding:
modelBuilder.Configurations.Add(new SomeTableDataMap());
At the bottom of my context class I did notice this got created:
public System.Data.Entity.DbSet SomeTableDatas{ get; set; }
Oh: I also put this in my constructor but it's for something else,
this.Configuration.LazyLoadingEnabled = false;
Seriously, this worked today, I've tried all of these solutions nothing worked for Update 4. I had this working in Update 2 and Update 3 using previous solutions. This is the most up-to-date solution for now.
Simple workaround that worked for me (after trying many other solutions suggested here and other places in vain...).
In the scaffolding dialog I just added a new DataContext e.g. TempContext. All the scaffolding worked as expected and then I could simply move the generated code in TempContext into my original DbContext and renamed the TempContext in the generated controllers to the original DbContext.
There are already multiple workarounds posted for this issue. And in this comment, I will try to provide the underlying issue why this may be failing. [With the hope to make people aware of the root cause]
Let's say, you have a DbContext (to be specific, child class of DbContext) in your application, and you are trying to use a model class (let's say Model) and the DbContext and scaffolding controllers / views.
I am guessing that the DbContext did not have a "DbSet< Model > Models {get; set;}" property on it but the DbSet was nevertheless added to the DbContext using code in OnModelCreating method.
In the above case, scaffolding first tries to detect DbSet property on DbContext (by reflection only - so that does not detect if OnModelCreating has code to add the DbSet) and given it's not, scaffolding adds a DbSet property to the DbContext and then tries to scaffold using that DbContext , however when running the scaffolding, we create an instance of DbContext and we also call OnModelCreating , and at that point, scaffolding fails because there are multiple DbSet types with the same model in the DbContext (one added by scaffolding and one configured in code in OnModelCreating).
[This happens not only for the model being used but also for related models in that model , scaffolding adds DbSet properties for all related models]
[Also, one doesn't see the added DbSet's after the scaffolding is done because scaffolding rolls back any changes if the operation did not complete successfully, like Jeff mentioned , the error message was poor initially and was improved to give some hint to the user but it's still not super clear what's going on]
This is a bug in scaffolding , a simple work around would be to use DbSet property on DbContext for all related models of your model class instead of configuring them in OnModelCreating.
I was getting a different error when trying to scaffold a controller with CRUD actions and views. In my case it was saying:
"There was an error running the selected code generator. Object instance
not set to an instance of the object."
The problem was hard to find: I created a table in SQL Server but forgot to set the Primary Key for the table. Setting the Primary key and updating Entity Framework's .edmx file solved the problem.
Hope it helps.
None of the rest of the answers worked for me. What I found out was that the issue only happened when scaffolding and adding Configurations using the Fluent API. So what I did was, instead of having separated files, each one having an Entity Configuration like this:
public class ApplicationUserMapConfiguration : EntityTypeConfiguration<ApplicationUserMap>
{
public ApplicationUserMapConfiguration()
{
ToTable("ApplicationUserMap", "Users");
HasKey(c => c.Id);
}
}
And then adding this configuration to the DbContext:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new ApplicationUserMapConfiguration());
}
I just added the whole configuration inside the DbContext for every entity:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
//ApplicationUser
modelBuilder.Entity<ApplicationUser>().HasKey(c => c.Id);
modelBuilder.Entity<ApplicationUser>().ToTable("ApplicationUser", "Usuario");
//Other entities...
}
Now I can scaffold perfectly. I already submited and issue on the Mvc GitHub.
Also, if another error message raises up saying:
There was an error running the selected code generator: ‘Exception has been thrown by the target of an invocation.’
You should modify your DbContext constructor to:
public YourDbContext() : base("YourDbContext", throwIfV1Schema: false) { }
None of answers of this post worked for me. I handled this issue creating new context class through plus button in Add Controller scaffolding dialog. Once VS created controller and views, I just remove the created context class and change the the generated controller code to use my existing context class.
Important: This process will add a new connection string for the new context, dont forget to remove it as well.
mine got fixed like this:
public virtual DbSet<Category> Categories { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//--> EntityTypeConfiguration<Your Model Configuration>
modelBuilder.Configurations.Add(new EntityTypeConfiguration<CategoryMapping>());
base.OnModelCreating(modelBuilder);
}
DOn't forget Ctrl + Shift + B so your code compile (i'm not sure for single solution, but since mine is in another project in same solution, it should get compiled first)
I solved it by adding a try/catch on the code to OnModelCreating function inside the context class.
Just keep the
base.OnModelCreating(modelBuilder);
outside your try/catch
I created an MVC 4 application using EF (Code First) which mapped to a mixture of tables and views which I created using SQL Management Studio which worked fine.
I have started a new MVC 4 project in much the same way as the first, using a completely different database, but this time anytime I try to use a model which maps to a view (not a table), an exception is raised saying that "An object with the name xxx already exists". The SQL profiler shows that EF is trying to create a table for my model.
I find that if I drop the views, let EF create the tables from the models, then delete the tables and replace them with view manually, the application will work for about 2 minutes, reading and using the information from my view, but eventually throwing the same exception.
I have no idea what is going on here.
The code that causes the exception is:
repository.Customers.OrderBy(c => c.AccountNumber);
where the model is:
public class Customer
{
public int Id {get;set;}
public string AccountNumber {get;set;}
public string Name {get;set;}
}
OK - the possible cause of this issue is hiding in your context file. There is probably a statement similar to the one below that is trying to update your database when the model changes.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer<MyContext>(new DropCreateDatabaseIfModelChanges<MyContext>());
}
I generally don't use this method. I prefer to delete the database and re-generate it using the package manager console. (Check out the update-database method of the package manager console)
Using Greg's hint I was able to arrive at the point where I simply added:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer<MyContext>(null);
}
to the context class and this has solved the issue. My understanding here is that I have told EF to do no initialisation, essentially having it map to an existing database that is maintained outside of the code first context.
I have voted up Greg's response as it was the help I needed but creating a new answer as it was the above that solved it eventually. I hope this was done right.
We're using Database first approach with EntityFramework.
We've several customers, and when we deploy new product version, we're now applying DB schema changes "manually" with tools like SQL Compare.
Is there a way how EF Migrations could help to apply changes to customers DB automatically?
As far as I know, EF Migrations is a product targeted at CodeFirst and doesn't support Database First operations.
CodeFirst assumes that you will never make any changes manually to the database. All the changes to the database will go through the code first migrations.
I think there is! You need to continue your way through the code first.
To do this, Suppose that you have the following DbContext that EF Db first created for you:
public class MyDbContext : DbContext
{
public MyDbContext()
: base("Name=DefaultConnection")
{
}
// DbSets ...
}
change that to the following to start using code first and all magic tools of it (migration, etc.):
public class MyDbContext : DbContext
{
public MyDbContext()
: base("YourDbFileName")
{
}
// DbSets ...
}
It causes that EF creates a new connection string using SQL Express on your local machine in your web.config file with the name YourDbFileName, something just like the early DefaultConnection Db first created.
All you may need to continue your way, is that edit the YourDbFileName ConStr according to your server and other options.
More info here and here.
Starting Entity Framework 4.1 you can do Code First Migrations with an existing database.
So first you have the database, create the model, enable migrations.
The most important thing to remember that you should run Enable-Migrations before you do any changes to the schema since it should be in sync between your db and code.
Just look for your DbContext child object and look for this method:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
If you comment this:
throw new UnintentionalCodeFirstException();
then the exception would not be thrown on migration operation. As you might imagine, the migration look for this part to know what are the configurations for each entity with what table or tables.
Sorry if I didn't go with more details, if you wish more, I'll be happy to edit this and make it better!