How to update EF models created as "Code First from datebase"?
I don't have a .edmx file (only a .cs one). How can I update it without deleting it and creating a new one ?
With Entity framework code first approach you do not need .edmx file, instead you need to to define a class derived from System.Data.Entity.DbContext class.
Below is a sample class which works as Data repository.
public class MusicStoreEntities : DbContext
{
public DbSet<User> Users{ get; set; }
public DbSet<Product> Products{ get; set; }
}
Now when you update model classes. you need to first enable migrations using Enable-Migrations command in Package Manager Console.
This command has added a Migrations folder to your project.
Now you need to run following command after making any changes in your model classes.
Update-Database –Verbose command in Package Manager Console.
This commaand will run migrations and update database accordingly.
For more details refer https://msdn.microsoft.com/en-us/data/jj591621.aspx
Related
Problem:
You have an existing database that you want to use with EntityFrameworks so that you can make database changes via classes. You also want to be able to use the migration features to switch between versions of the database.
Unfortunately this doesn't work out of the box with an existing database, but you can use the Reverse POCO generator to reverse-engineer your db as if you wrote it from scratch.
Hopefully my step-by-step solution will benefit others, I'm sure I'll be referring to it again in 6 months.
Create new project called MyEF (class library project)
Install the EntityFramework Reverse POCO generator either from here, or within Visual Studio menu Tools|Extensions and Updates menu. select Online|Visual Studio Gallery|Templates|Visual C#|Database, install the EntityFramework Reverse POCO generator.
Using Package Manager console, install EntityFramework by Install-Package EntityFramework
Add a new C# item called MyDB.tt using the template: EntityFramework Rever POCO Code First Generator
Add a connectionStrings section to the app.Config class and point to your database.
e.g.
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=CP8;Initial Catalog=TestDB;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=False;" providerName="System.Data.SqlClient" />
</connectionStrings>
In the file MyDB.tt, change "MyDbContext" to "DefaultConnection" or whatever your connection name is. Save the TT file and the Reverse POCO generator will reverse engineer the database and build your code-first classs for you.
If your database has a _MigrationHistory table, delete it!
In the package manager console (PMC) issue the following
Enable-Migrations –EnableAutomaticMigrations -Force
add-migration Initial
Go to your migrations folder and replace the contents of your XXX_Initial.cs class with
namespace MyEf.Migrations
{
using System;
using System.Data.Entity.Migrations;
public partial class Initial : DbMigration
{
public override void Up()
{
}
public override void Down()
{
}
}
}
From the PMC, issue: update-database
Change your Model by editing the adding a new property in MyDb.cs to the MyTable class:
// MyTable
public class MyTable
{
public int Id { get; set; } // Id (Primary key)
public string Name { get; set; } // Name
public string Sex { get; set; } // Sex
public int? Age { get; set; } // Age
public bool AmIAwesomeOrWhat { get; set; }
}
Rebuild the solution
Issue a command to save your new migration, and update the database
add-migration MyNewProperty
update-database
The following commands will switch to whatever Migration you want.
update-database -targetmigration:Initial
update-database -targetmigration:MyNewProperty
I have created model classes and using following context in my mvc project on VS2013 and using EF 6.1
public class DataBase : DbContext
{
public class DataBase : DbContext
{
public DataBase()
: base("Db")
{
}
public DbSet<table> table{ get; set; }
}
}
"Db" is my connection string everything ,everything run good but table are not created on my database
Did you try this?
public class DataBase : DbContext
{
public class DataBase : DbContext
{
public DataBase()
: base("Name=Db")
{
}
public DbSet<table> table{ get; set; }
}
}
Set :base() to "Name=Db".
In ef 6 they changed how things work and therefore you need to do some manual steps to be able to generate the database. You have a couple of options I think:
1. Use the packed manager console and run the Update-DataBase command. (You'll have to figure out which flags to use) This might require you to make a blank db with the expected name before running update.
2. Change your database initializer command to:
Database.SetInitializer<UserDbContext>(new MigrateDatabaseToLatestVersion<UserDbContext, Configuration>());
This should make your code always update/create the database. Probably not what you want for production environment though..
3. You create your own initializer, which also has the benefit of seeding data to database on creation. Have a look at http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net-mvc-application <-- towards the end of the article there is an example of such an initializer. The chapter heading is "Set up EF to initialize the database with test data"
i have somehow gotten my EF5 project into a state where I can't proceed.
When I do an 'update-database' i get:
Unable to update database to match the current model because there are pending changes and automatic migration is disabled. Either write the pending model changes to a code-based migration or enable automatic migration. Set DbMigrationsConfiguration.AutomaticMigrationsEnabled to true to enable automatic migration.
You can use the Add-Migration command to write the pending model changes to a code-based migration.
ok, fine, so i try to 'add-migration', and i get:
Unable to generate an explicit migration because the following explicit migrations are pending: [ ]. Apply the pending explicit migrations before attempting to generate a new explicit migration.
20 GOTO 10 ??
what am i supposed to do at this point? (beyond switching to NHibernate?)
What worked for me was:
Reverting all my changes (making a backup first) back to a known good state.
Doing add-migration DummyMigration. That produced some spurious changes that I commented
Called update-database to add the migration + metadata to the [__MigrationHistory] table.
Make the changes I needed (from the backup of the code I took earlier).
Do the normal add-migration/update-database.
Not ideal, and would be cool to see if there's a better solution, but that worked for me.
For me the issue was that we had renamed the namespace of the migration 2014123456_Initial.cs.
But VS had not regenerated the namespace in its associated 2014123456_Initial.Designer.cs.
Once the Designer.cs was changed to use the same namespace, it all started working again.
(also posted this as an answer here because both questions are so similar)
I changed the following value in my Configuration.cs class from false to true.
AutomaticMigrationsEnabled = true;
In App_Data folder I renamed my project's database - the file with .mdf ending (so a new one will be created), and in Package Manager Console I entered the following command:
update-database
after which the pending migrations ran smoothly.
Note this worked for me, but I'm not 100% if this is the best practice. In any case this Entity Framework Code First guide for migrations says:
"If you get an error that indicates a table already exists and can't be created, it is probably because you ran the application after you deleted the database and before you executed update-database. In that case, delete the Movies.mdf file again and retry the update-database command. If you still get an error, delete the migrations folder.."
Also about AutomaticMigrationsEnabled = true; this MSDN article, Data Points : A Code First Migrations Mystery: Solved tells "Migrations can run automatically, meaning that model changes will be discovered and migrations corresponding to changes will be created and executed on the database. All of this happens at run time during database initialization. Automatic migrations are handy for simple apps, but you have very little control over them and I typically don’t recommend enabling them. I was happy when Code First switched the default to false."
Update-Database –TargetMigration <second_last_migration>
Add-Migration <full_name_including_timestamp_of_last_migration>
You need to include the timestamp so that migrations knows you want to edit the existing migration rather than scaffolding a new one. This will update the metadata for the last migration to match the current model.
Update-Database
Source https://learn.microsoft.com/en-gb/ef/ef6/modeling/code-first/migrations/teams#resolving-the-merge-conflict
I did mistake in creation database
using System.ComponentModel.DataAnnotations;
using System.Globalization;
namespace ProductsManager.Models
{
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Production { get; set; }
public string Size { get; set; }
public decimal<--- Price { get; set; }
public string Barcode { get; set; }
}
}
after add-migration Initial I realized and changed code to public int Price { get; set; }
did same add-migration DummyMigration and its created in migration folder
080372472_dummyMigration
namespace IdetityBeta.Migrations
{
using System;
using System.Data.Entity.Migrations;
public partial class DummyMigration : DbMigration
{
public override void Up()
{
AlterColumn("dbo.Products", "Price", c => c.String());
}
public override void Down()
{
AlterColumn("dbo.Products", "Price", c => c.Decimal(nullable: false, precision: 18, scale: 2));
}
}
}
So then update-database and problem was solved
I got around this by
Run "Update-Database -Script -Force"
note the last explicit migration attempted before the error "Unable to update database..."
Run "Update-Database -Script -TargetMigration [lastmigration]" using the last migration noted from the previous attempt
I could then run in the script and add a new migration. This is on EF6 and Nuget 2.8 - it may not have worked when the question was posted.
This can happen when you are trying to merge with migration which has the same base as your migration because of which there is model difference in one of migration schema even though that table exists
To solve this problem what you can do is create merge migration by command
Add-Migration -IgnoreChanges
followed by migration name
This creates an empty migration with the current model as a snapshot. Thus this will solve your model difference problem and your tables and models will be in sync
Apparently IMigrationMetadata.Target encodes the state of the EF model.
Can I use this to reconstruct the model for a particular migration?
Yes, it is possible. I was myself curious what exactly those magic resource strings were storing. By digging into the Entity Framework source (see the DbMigrator.GetLastModel() method), I found out that the IMigrationMetadata.Target just stores a base-64 string containing gzipped XML data. To test this, I created a new console application containing a simple code-first model defined as follows:
public class ContactContext : DbContext
{
public virtual IDbSet<Contact> Contacts { get; set; }
}
public class Contact
{
public int Id {get; set;}
public string FirstName { get; set; }
public string LastName { get; set; }
}
Then I created a migration using the NuGet Package Manager Console:
PM> Enable-Migrations
PM> Add-Migration MyMigration
Next I added the following code to my application's Main() method to decode the value in that string and dump it to the console:
var migration = new MyMigration();
var metadata = (IMigrationMetadata)migration;
var compressedBytes = Convert.FromBase64String(metadata.Target);
var memoryStream = new MemoryStream(compressedBytes);
var gzip = new GZipStream(memoryStream, CompressionMode.Decompress);
var reader = new StreamReader(gzip);
Console.WriteLine(reader.ReadToEnd());
This outputs an EDMX file representing the Entity Data Model associated with my DbContext that created the migration. If I write this output to a file with the .edmx extension, I'm able to open it with Visual Studio and view it in the Entity Designer.
Then if for some reason I wanted to regenerate the DbContext and entity classes that produced the model, I would need only do the following:
Add the .edmx file to a Visual Studio project.
Install the EF 5.x DbContext Generator for C# if I don't already have it.
Add the related T4 templates by selecting Add -> New Item from project node context menu.
Modify the newly added .tt files, replacing $edmxInputFile$ with the name of my .edmx file.
Watch as the two templates magically regenerate my code-first types to their respective .cs files.
Hope that answers your question! :-D
I created a small console app to export EDMX from the Model column of the __MigrationHistory table https://github.com/andreydil/EfMigrationModelDecoder
You can choose specific migration using /migration parameter, i.e:
EfMigrationModelDecoder.Cli.exe "<connectionString here>" /migration:Init
I created a PowerShell script to extract the latest migration from a DB to a edmx-file.
https://gist.github.com/otto-gebb/93d021c8fd300646dba0073a77585a94
You can also use SQL...
SELECT CONVERT(xml, DECOMPRESS(Model)) FROM [dbo].[__MigrationHistory] WHERE MigrationId = 'NameOfMigration'
I am using DB First EF 4.1 and I am adding DbContextGenerator tt template to my model. This is all great, but I end up with classes like this:
public partial class t_city
{
public t_city()
{
this.t_neighborhood = new HashSet<t_neighborhood>();
}
public int city_id { get; set; }
public string city_name { get; set; }
public virtual ICollection<t_neighborhood> t_neighborhood { get; set; }
}
This is super ugly. I modified the template to generate properties in camelcase, but that breaks the mapping onto tables and columns. Is there way to get clean class names and still preserve the mapping?
EDIT
Looks like it's possible by renaming the objects inside the Entity Model file. The only question remains, is it possible to automate the renaming using a function, or does it have to be done manually each time?
Thanks!
You need to do it manually but that's needed only once for each entity / property. These changes are not deleted when you update your model from the database.
The only automation can be implemented as some processing of EDMX file. It is XML with defined schema so you can process that XML in your custom tool or XSLT transformation and automatically change property and entity names in CSDL and MSL.