EF Migrations for Database-first approach? - c#

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!

Related

UnintentionalCodeFirstException | Entity Framework Unit Testing with Effort.Ef6 using Database First

The situation
I want to enable unit testing of my DbContext based on entity framework 6. I have created my DbContext and my models with the database first approach and now have an .edmx designer file.
The problem
My automatically created DbContext does override the DbContext.OnModelCreating method like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
I am trying to create a new instance of my DbContext in my mocked data access service based on the information of this article. My code doesn't run into Database.SetInitializer; like the author of this blog post pointed out. My constructor looks exactly like his. My DbContext initialization looks like this:
public DatabaseEntities(DbConnection connection)
: base(connection, true) { }
Which results in following exception when reaching the previously mentioned overridden OnModelCreating
System.Data.Entity.Infrastructure.UnintentionalCodeFirstException: 'The context is being used in Code First mode with code that was generated from an EDMX file for either Database First or Model First development. This will not work correctly. To fix this problem do not remove the line of code that throws this exception. If you wish to use Database First or Model First, then make sure that the Entity Framework connection string is included in the app.config or web.config of the start-up project. If you are creating your own DbConnection, then make sure that it is an EntityConnection and not some other type of DbConnection, and that you pass it to one of the base DbContext constructors that take a DbConnection. To learn more about Code First, Database First, and Model First see the Entity Framework documentation here: http://go.microsoft.com/fwlink/?LinkId=394715'
There are plenty of questions on stackoverflow which focus on unit testing with effort while using the database-first apporach, but no one seems to have similar problems like me.
What I have already tried to do
Searching the internet a long time for a solution.
Uncomment the overridden OnModelCreating().
I have already tried to apply this solution without success.
Mock my DbContext with Moq, which is definitely not an option.
The question
How can i create and use an in-memory database (with effort)?
Additional information
When I uncomment the OnModelCreating(), an exception will be thrown at the first access to the DataContext. E.g.:
DbConnection effortConnection = Effort.DbConnectionFactory.CreatePersistent("MockedDatabaseEntities");
using (DatabaseEntities dataContext = new DatabaseEntities(effortConnection))
{
dataContext.Students.Count(); // Exception throws here
}
System.Data.Entity.ModelConfiguration.ModelValidationException: 'One or more validation errors were detected during model generation:
MyApplication.Shared.Model.KeyValuePair: : EntityType 'KeyValuePair' has no key defined. Define the key for this EntityType.
KeyValuePairs: EntityType: EntitySet 'KeyValuePairs' is based on type 'KeyValuePair' that has no keys defined.'
The problem was that I had to specify the key for my KeyValuePair dataset.
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<KeyValuePair>().HasKey(x => x.Key);
base.OnModelCreating(modelBuilder, null);
}
Thank you very much Robert Jørgensgaard Engdahl
!
If anyone is looking for the solution for db-first approach, this worked for me:
string connStr = #"metadata=res://*/Model.csdl|res://*/Model.ssdl|res://*/Model.msl;";
DbConnection connection = EntityConnectionFactory.CreateTransient(connStr);
return new MyDatabaseContext(connection);
I got the connStr part from my web/app.config.
Also, I did not touch OnModelCreating.

Entity Framework 7 - run seed at the end of the migration [duplicate]

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.

Entity Framework: Only Seed when building initial database

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.

EF migration shows empty Up() Down() methods

I have a local database that is currently in it's second version and should now go to it's third version.
The code for the previous migrations was generated by another programmer so I am assuming I am doing something wrong here.
In my model there are around 30 classes, and inside the model folder there is a mapping folder and it contains the mappings for those 30 classes.
So now I added 1 new class in the same manner as those previous classes and then run the add-migration command in the Package Manager Console.
Infortunately I get an empty migration Up() and Down() method.
When I look in the database there is a __migrationHistory available with the previous 2 migrations. If I run my application now, the third migration is also added but obviously the new table is not being created because it's not in the Up() method.
What could I be doing wrong?
I think something is going wrong when scaffolding the previous migrations... It's like it can't find the new Code-First classes I have added.
This is my command:
add-migration "1.2" -verbose -ProjectName "MyEFproject"
I am assuming that the scaffolding doesn't know where to look for the new class... or is this by convention that all model classes are just expected to be in the project?
Result of add-migration:
namespace MyProject.Migrations
{
using System;
using System.Data.Entity.Migrations;
public partial class _1002 : DbMigration
{
public override void Up()
{
}
public override void Down()
{
}
}
}
Sample of new Model Class:
using System;
using System.Collections.Generic;
namespace MyProject.Models
{
public partial class MyTable
{
public string SomeId { get; set; }
public string SomeText { get; set; }
}
}
Sample of new Mapping class
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity.ModelConfiguration;
namespace MyProject.Models.Mapping
{
public class MyTableMap : EntityTypeConfiguration<MyTable>
{
public MyTableMap()
{
// Primary Key
this.HasKey(t => t.SomeId);
// Properties
this.Property(t => t.SomeText)
.IsRequired()
.HasMaxLength(30);
// Table & Column Mappings
this.ToTable("MyTable", "database");
this.Property(t => t.SomeId).HasColumnName("SomeId");
this.Property(t => t.SomeText).HasColumnName("SomeText");
}
}
}
Thank you,
You need to add your table to your implementation of the DbContext class, e.g.
public class MyDatabaseEntities : DbContext {
public virtual DbSet<MyTable> MyTable { get; set; }
}
While rolling back an existing EF Core Data Context back to empty, my migrations wouldn't generate until I removed the ApplicationDbContextModelSnapshot that accompanied the migrations.
This class is auto-generated and needs to align with your current migration level.
I was able to fix this issue by deleting a record of last migration from _MigrationHistory table.
This record had been incorrectly created before I added DbSet for new model object to DbContext class.
After this deletion new migration was created with correct Up() and Down() methods.
I had this problem because I forgot to add {get; set;} after my variable names
You need to add your table to your implementation of the DbContext class, e.g. While rolling back an existing EF Core Data Context back to empty, my migrations wouldn't generate until I REMOVED the ApplicationDbContextModelSnapshot that accompanied the migrations.
In my case, the datacontext project is a class lib project. It is different from the startup project which is asp.net mvc 5 project. Now by mistake the connection string in the startup project is pointing to a different database.
So ensure that datacontext project and startup project point to the same database. Also use the full command as mentioned in the question like the following. You can include -Force as well.
add-migration "InitialMigration" -verbose -ProjectName "MyEFproject" -Force
Also: Make sure any new properties you've added are public!
In my case I was doing a migration where I added fields to an existing table and was ending up with empty Up and Down methods,
I had something like this:
public bool ExistingField { get; set; }
bool NewField { get;set; }
Can you spot the difference...?
If you make this mistake rerun the migration with the same name (you probably will need to add the -Force parameter to scaffold it full).
PS. Always make sure your project builds fully before attempting to do any kind of EF command. If your project doesn't already build you're asking for trouble.
You need to add your MyTable in Dbset and your issue will be resolved:
public DbSet<MyTable> MyTables { get; set; }
I was getting empty migrations added when I had mistakenly related two tables using a 1-many relationship rather than a many-many (i.e. i forgot one of the navigation properties). I had a seeding file that was expecting a many-many relationship and was subsequently failing during the migration causing the migration to fail. Unfortunately there was no output that made it obvious that was the problem and it was only by using the Entity Framework Power Tools (v4 but installed in VS2015) did i visually see the incorrect relationship and realize it was probably the cause.
I had to Update-Database with the latest migration before the empty one appending this parameter -TargetMigration:"{your-migration-name}".
Probably it will tell you that there will be data loss from the next buggy one we tried. If you can afford it append -Force to it.
Then I tried to add my new Add-Migration and it wasn't empty.
Final thing that you may need to do if above is throwing exception is to go SQL Server Management Studio and delete the last Automatic migration and try to add it again.
if new tables added to Context
just remove new table in "Migration/ExampleContextModelSnapshot"
I had the same issue on EFcore. When renaming Phone -> mobile, the migration came up empty.
My DbContext :
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MyUser>()
.Property(c => c.Mobile)
.HasColumnName("phone");
}
Problem was using .HasColumnName("phone") was overriding the actual property name so EF probably couldn't see any change.
Changing string value made it work.
I had this exact issue after I wanted to add an extra column to my database. Because my data would not seed unless the tables were empty, I deleted all the tables and the migrations to recreate the tables. When I tried to migrate, the migration had empty up and down methods.
I solved this by deleting the snapshot file as this was creating the issue. So I deleted all the migrations and the snapshot file, added the migration again and ran update database. The tables and migrations were successfully updated with my new column.
A better way to do this though is to run the down method and drop the tables like that if you are working on test data. Obviously this is bad in the real world to drop tables.
To me the problem was that Id property that should correspond to table id was named FeedbackId.
I changed to "Id" and then Up/Down weren't empty anymore.
Dunno if that can help somehow
If your project is small, i.e. you do not have too many migrations yet, you can delete all from your Migration folder. After that, add the migrations again.
I think this also happens when u try to do migration without any changes in the models. eg when you do migration one and succeed, when u try to do migration2 without doing any changes in any of the models, it will create empty UP and Down.
From the perspective of a complete Entity Framework (Core) beginner:
Create your class which will become your table
You can have subclasses with many-to-many or one-to-one relationships.
In step 3 you see the context where both properties have a one-to-one relationship.
Ensure you have one DbContext
If you have more than one DbContext you need to specify which context you want to add the migration to with the -Context parameter.
Add your class to your DbContext as shown by #CondingIntrigue
As a reference The Entity Framework Core DbSet
public class AccountContext : DbContext
{
public DbSet<Account> Accounts { get; set; }
public DbSet<SecretIdentity> SecretIdentity { get; set; }
}
Enter Add-Migration
In my case, I was encountering similar problems with Visual Studio Code.
I have fixed these by doing the following:
Check inside your ContextModelSnapshot : ModelSnapshot
Comment Model Entity Definition…
Delete your migration files related to these entity
Delete the migrations from the dbo.__EFMigrationsHistory table
Compile your solution.
Run the following commands:
dotnet ef migrations add migrationName -p ProjectContainer/
dotnet watch run
Temprorary remove
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
and then do initial create
Add-Migration InitialCreate
If after adding your class in the dbContext and your migration is still empty: do the following:
In your DbContextModelSnapshot class, remove every related code to that class name that you are trying to apply add-migration on. Save the DbContextModelSnapshot.cs and use the Add-Migration "Added_filename"
This work for me.
In my case ,I deleted Migration folder completely. As long as I didn't remove the "ApplicationDbContextModelSnapshot" and all previous migrationas it didn't work.
For me it was because I hadn't add Configuration files.
onModelCreating:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfigurationsFromAssembly(typeof(AppDbContext).Assembly);
}
and add configurations in same assembly derived from IEntityTypeConfiguration<T> where T is your model.
I missed adding
{get;set}
After adding getter and setter, up and down methods are not empty.

About Code First Database Evolution (aka Migrations)

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

Categories