I have read this blog: which explains the difference between Database Initializer seeds and Migration seed methods.
I am working on a project, that uses code-first Entity Framework, with migrations enabled. A Database Initializer seed is present and it will execute on my local database, when the database is created.
But in the production environment, I do not have the rights to add databases myself. I need to run update-database -script from package manager console on an empty newly created database and then execute the migrations manually.
As I do not have direct access from my development environment to the production database server, I am thinking out loud: there is no gain in rewriting the Database Initializer to a Migrations Seed.
How can I obtain the script (SQL), that is the insert statements, defined in the Database Initializer seed method?
Of course I can :
run update-database on an empty existing database. (no seed method is executed)
run update-database on a non-existing database. (seed method is executed)
Do a SQL compare between the 2 databases and get the INSERT queries that way.
But there should be an easier way right?
Why does the update-database -script not show the INSERT statements from the database initializer seed method in the first place?
I am not sure if the logging described in Entity Framework Logging and Intercepting Database Operations will catch the SQL from the DatabaseInitializer. If not you can try to find a 3rd party profiler to catch your SQL. Personally, I use ORM Profiler and it catches everything, however it is not free.
And yes, there should be an easier way.
Related
I have an existing database with data in it. There are (a lot of) sql files which insert a set of starting data.
The project is being refactored to code-first approach, so I wan't to move the init sql files into a context initializer.
Is there a way to achieve this with a tool or script, without having to manually re-type all the sql files?
You can use EF Migration to perform this kind of refactorization.
And on the migration, you can execute custom SQL scripts. Here is an example :
https://entityframeworkcore.com/knowledge-base/46638380/execute-custom-sql-script-as-part-of-entity-framework-migration
I have tried lots of variations of EF migration v6.0.1 (from no database, to empty databases to existing databases) and I have a particular problem with Azure DB instances not being able to correctly be created on first deploy using Octopus deploy.
There are a number of places where this could be going wrong, so I thought I would check some basics of EF Code First migration with you fine people if I may:
If I create a code-first model, and know that the database does not exist in the intended target database server on Azure. With the default of 'CreateDatabaseIfNotExists' approach and with AutomaticMigrations disabled;
If I then call 'migrate.exe' with the assembly containing my DbContext and migration Configuration will I get a new database created with the current state of the model? or will I get a new database with nothing in it? i.e. do I need to explicitly 'add-migration' for the initial state of the model?
I have read in the documentation that the database instance should be created automatically by the migration process, but no one states clearly (at least to me) that this newly created database will be generated with the current model without a formal 'initial state' migration created.
So the question is this: do I need an explicit migration model generated for migrate.exe to work from?
Through whatever means I try, I get a database but the application launches with the unfriendly message "Model compatibility cannot be checked because the database does not contain model metadata. Model compatibility can only be checked for databases created using Code First or Code First Migrations." Remembering that this is the same application library that just created the database in the first place (from scratch) I fail to understand how this has happened!
I did manually delete the target database a few times via SQL Server management studio, is this bad? Have I removed some vital user account that I need to recover?
Migrations and the Database Initializer CreateDatabaseIfNotExists are not the same.
Migrations uses the Database Initializer MigrateDatabaseToLatestVersion, which relies upon a special table in the database _MigrationsHistory.
By contrast, CreateDatabaseIfNotExists is one of the Database Initializers which relies upon the special database table EdmMetadata. It does exactly as it implies: Creates a database with tables matching the current state of the model, i.e. a table for each DbSet<T>, only when the database does not exist.
The specific error you have quoted here, Model compatibility cannot be checked because the database does not contain model metadata., occurs due to the existence of DbSet<T> objects which were added to the code base after the initial database creation, and do not exist in EdmMetadata.
There are 4 basic Database Initializers available, 3 of which are for use when migrations is not being used:
CreateDatabaseIfNotExists
DropCreateDatabaseWhenModelChanges
DropCreateDatabaseAlways
Also note, the 4th Initializer, MigrateDatabaseToLatestVersion, will allow you to use Migrations even if AutomaticMigrations is disabled; AutomaticMigrations serves a diffierent purpose, and does not interact with the Database Initializers directly.
If you intend to use Migrations, you should change the Database Initializer to MigrateDatabaseToLatestVersion and forget about the other 3. If, instead, you intend to not use Migrations, then the choice of Initializer is situational.
CreateDatabaseIfNotExists will be more appropriate when you are certain that your data model is not undergoing active change, and you only intend to be concerned with database creation on a new deployment. This Initializer will elp ensure that you do not have any issues with accidental deletion of a database or live data.
DropCreateDatabaseWhenModelChanges is most appropriate in development, when you are changing the model fairly often, and want to be able to verify these changes to the model. It would not be appropriate for a production server, as changes to the model could inadvertently cause the database to be recreated.
DropCreateDatabaseAlways is only appropriate in testing, where your database is created from scratch every time you run your tests.
Migrations differs from these 3 Database Initializers, in that it never drops the database, it instead uses Data Motion to execute a series of Create Table and Drop Table SQL calls.
You also can use Update-Database -Script -SourceMigration:0 in the Package Manager Console at any time, no matter which Database Initializer you are using, to generate a full SQL script that can be run against a server to recreate the database.
Firstly, many thanks to Claies who helped me get to the bottom of this problem. I have accepted his answer as correct as ultimately it was a combination of his response and a few additional bits of reading that got me to my solution.
In answer to the actual posts question 'Do I need a migration for EF code first when the database does not exist in SQL Azure?' the answer is yes you do if you have disabled automatic migrations. But there is a little more to be aware of:
The Azure aspects of this particular problem are actually irrelevant in my situation. My problem was two-fold:
The migration being generated was out of sync with respect to the target model. What do I mean? I mean, that I was generating the migration script from my local database which itself was not in sync with the local codebase which created a migration that was incorrect. This can be seen by comparing the first few lines of the Model text in the __MigrationHistory. This awareness was helped by referring to this helpful post which explains how it works.
And more embarrassingly (I'm sure we've all done it) is that my octopus deployment of the web site itself (using Octopack) somehow neglected to include the Web.Config file. From what I can tell, this may have occurred after I installed a transform extension to Visual Studio. Within my nuget package I can see that there is a web.config.transform file but not a web.config. Basically this meant that when the application started up, it had no configuration file to turn to, no connections string at all. But this resulted in the slightly misleading error
Model compatibility cannot be checked because the database does not
contain model metadata.
Whereas what it should have said was, there isn't a connection string you idiot.
Hopefully this helps people understand the process a little better after reading Claies answer and also that blog-post. First though, check you have a web.config file and that it has a connection string in it...
I have searched but couldnt find any useful thing about generating automatically basic CRUD stored procedures when creating the database in code first approach. I am wondering is there a way to do this simply or i should create all the CRUD stored procedure by old fashion?
It is indeed possible to use Migrations with a Code First Database to generate stored procedures for CRUD operations in Entity Framework 6 and beyond. Note that this is not possible in this manner with Entity Framework 5 and earlier, though you could still use raw SQL calls.
Define your entity in the normal manner, and add a DbSet for the entity to your DbContext class.
Modify the OnModelCreating method of the DbContext to add the following entry: modelBuilder.Entity<SomeEntity>().MapToStoredProcedures();.
Using the Package Manager Console, generate a new migration with add-migration, i.e. add-migration SPGenerate.
Inspect the Up method of your migration to tweak the Stored Procedures to your liking.
Commit the migration to the database by issuing update-database in the Package Manager Console.
What am I doing wrong. I have got a user DbContext setup and working when I originally created the Code-First with powershell it all worked fine.
I implemented Database Initializer as expected on application start.
Database.SetInitializer<UserDbContext>(new CreateDatabaseIfNotExists<UserDbContext>());
Just to test out if it really creates the database I actually dropped the database and now I am stuck the database will not be created. I am using SQL Server 2012, any idea what could be wrong.
The error message I am getting is
System.InvalidOperationException: Migrations is enabled for context 'UserDbContext' but the database does not exist or contains no mapped tables. Use Migrations to create the database and its tables, for example by running the 'Update-Database' command from the Package Manager Console.
I have tried the same from Package Manager console and it is still give me the same message.
Finally figured the solutions, not sure why or what. Changed my Database initializer to MigrateDatabaseToLatestVersion instead of CreateDatabaseIfNotExists worked.
Database.SetInitializer<UserDbContext>(new MigrateDatabaseToLatestVersion<UserDbContext, Configuration>());
Edit:
With your new error message the problem comes from you having migrations enabled and already ran a migration (probably the first creation of the database) and since you dropped the DB the migration history has been lost. If your not using Automatic migrations you can not go in and make changes to the database your self and expect code-first to know about it. Try disabling migrations and re-enabling them to see if that clears out the migration history.
You will need to make a call into the DB either as a read or insert of data for the DB to initially be created. The code you use only tells EF how to deal with a database if one does not exist when it tries to find it. For me I use the method outlined at http://www.codeproject.com/Tips/411288/Ensure-Your-Code-First-DB-is-Always-Initialized
I'm following the Entity Framework tutorial on:
Link
I've downloaded the source code, and ran. The project works fine (using the default connection string).
<add name="SchoolContext" connectionString="Data Source=|DataDirectory|School.sdf" providerName="System.Data.SqlServerCe.4.0" />
Next i've changed the connection string to connect to a remote server (which successfully connects). However the tables aren't created and when running the application and accessing the controller I get the following error.
Error:
Model compatibility cannot be checked because the database does not contain
model metadata. Model compatibility can only be checked for databases created
using Code First or Code First Migrations.
My database user is 'dbowner' so I wouldn't imagine it's database access issues.
I'm new to EF, and don't know much about Code First Migrations. Have you come across the above error, and would Code Migrations solve this issue? If so why?
From my reading (please correct me if I am wrong) the scenario here is that you have an existing (perhaps empty) database on a remote server that you wish to put your EF code-first work into.
The error is coming about because, I think, EF is looking for a _MigrationHistory table (metadata about what EF code-first migrations have been run against it etc) and can't find it. There is some reasonable coverage of this table here for some background/interest reading.
So to resolve the issue, I think the steps to take are:
Initialise your database so that it acknowledges the EF code-first stuff
Update the database, rolling forward all your migrations to date
I found some good coverage of how to do this here. This blog also has some good coverage of EF topics in general
PS. I am guessing that your .dsf/SQL Compact Edition database wouldn't have had this problem because EF code-first would have created it for you on first run so it was already acknowledged as being a code-first database.
Here is a link to Entity Framework Power Tools. It is made for creating models by 'Reverse Engineering' your Database on a remote server. You can then easily access this database using EF.
Reverse Engineer Code First - Generates POCO classes, derived DbContext and Code First mapping for an existing database
Both of the initializer methods which I had tried fail when the database already exists:
Database.SetInitializer<Context>(new Initializer());
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<Context>());
However it is possible to force the database to be dropped using:
Database.SetInitializer(new DropCreateDatabaseAlways<Context>());
The following SO post provides the answer to my question:
Setting up a Entity Framework Code First Database on SQL Server 2008
I've tried a combination of the two, and have decided that the best solution is to manually go into SQL Management studio and DROP the database, and re-create it using the initializer as this allows me to Seed the contents of the database.
Database.SetInitializer<Context>(new Initializer());
See here for more information on Seeding the database as it is also quite an unstable processess!
How can I get my database to seed using Entity Framework CodeFirst?