Code First for SQL Server 2005? - entity-framework

My development DB is 2008 R2 which is where Code First generates the local database with DropCreateIfModelChanges.
My method of deploying to production is to generate scripts from local DB, including data and run that in production. This creates all of the tables, including the EdmMetadata table and populates it with the hash.
Works:
Run script in a different 2008 R2 instance, change connection string for the Entity model to point to this production instance, run application.
Does not work:
Run script in a different 2005 instance, change connection string for the Entity model to point to this production instance, run application. I get an error indicating the model has changed.
I think this doesn't work because the DB compatibility version is a part of the hash. thus in production it generates a hash and compares it to the hash stored in the EdmMetadata table. The new hash is different because it is generated against a 2005 DB.
I am guessing I would not have this problem if I was generating a 2005 DB locally and deploying that to a 2005 production instance. However I don't have 2005 installed and would rather not require all the developers to have to install it, when 2008 supports a 2005 compatibility mode already.
How can I force EF to generate a DB in 2005 compatibility mode?

If the only problem is the model compatibility check, then you can disable database initializers for your context when running in the production environment where you presumably don't need to initialize the database anyway. You can do this in code like so:
Database.SetInitializer<MyContext>(null);
But it's probably better to do it in the app.config/web.config for your production application like so:
<entityFramework>
<contexts>
<context type="MyNamespace.MyContext, MyAssembly" disableDatabaseInitialization="true" />
</contexts>
</entityFramework>
You will need to update to EF 4.3 for this syntax--see http://blogs.msdn.com/b/adonet/archive/2012/01/12/ef-4-3-configuration-file-settings.aspx. There is also a way to do it in EF 4.1: See http://blog.oneunicorn.com/2011/03/31/configuring-database-initializers-in-a-config-file/.
You could also try just updating to to EF 4.3 which doesn't use the EdmMetadata table anymore--it uses the __MigrationHistory table instead. This checks for model compatibility in a different way. It may still flag a difference if Code First would have generated a different database for 2005 than it did for 2008, which is occasionally the case.
You could install SQL Server 2005 Express on your dev box. It's free and would match your production environment better.
Finally, if none of the above work and you need to force Code First to generate a 2005 model/database, then you can do that, but it means using lower-level building blocks. First, you'll need to create the DbModelBuilder yourself and call Entity for each of the entity types for which you have a DbSet declared on your context:
var modelBuilder = new DbModelBuilder();
modelBuilder.Entity<User>();
modelBuilder.Entity<Blog>();
You can do other fluent configuration here or use data annotations as normal. OnModelCreating will not be called so don't put fluent calls there--move them here instead.
Once you have a configured DbModelBuilder you'll need to build and compile to get a compiled model that can be passed to DbContext. It is at this stage that you can pass in "2005" as the provider manifest token.
var compiledModel = modelBuilder
.Build(new DbProviderInfo("System.Data.SqlClient", "2005"))
.Compile();
You should now cache this compiled model in your app domain so that you only build and compile it once. (Normally DbContext does this for you when it builds the model, but if you build the model yourself then you need to also do the caching yourself.)
Finally, you will need to pass the compiled model to a constructor of your context every time you need to use it and have that constructor pass the model on to the base constructor.
public class MyContext : DbContext
{
public MyContext(DbCompiledModel model)
: base(model)
{
}
public DbSet<User> Users { get; set; }
public DbSet<Blog> Blogs { get; set; }
}
There are other constructor overloads for passing a name or connection string as well if you need them.

Related

Database first with Identity in .NET Core and Entity Framework Core

I would like to use a Database First approach to managing my database with EF Core, and not just for the initial database creation. I'm using this command to generate my entity models and mapping code:
Scaffold-DbContext "Server=(localdb)\mssqllocaldb;Database=MyDB;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models/Entities -f
Now this works fine. I'm just struggling with identity integration. Currently I have two separate contexts, the one generated by the scaffolding command and an identity context that looks like this:
public class IdentityContext : IdentityDbContext<ApplicationUser> {
public IdentityContext(DbContextOptions<IdentityContext> options)
: base(options) {
}
protected override void OnModelCreating(ModelBuilder builder) {
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
}
}
Both contexts read from the same database and are registered like this:
services.AddDbContext<ApplicationContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddDbContext<IdentityContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
Is it reasonable to have two separate contexts? Will it cause future problems as I start creating relationships between users and other models? I couldn't find anything in the docs regarding continued use of db-scaffold to generate my entity models and mappings.
Let me know if I can clarify anything.
ORIGINAL CONTEXT
Okay so clearly my original question wasn't any good.
I'd just like some clarification on if my Database First workflow with .NET Core and Entity Framework is the right way. I've read all the articles I can find about using Database First, which all seem to end with: "now you have scaffolded your database so can start using Code First migrations". I want to continue writing my SQL and just keep mapping it to entities.
To manage and update my application I'm using the excellent DbUp project. So I write my scripts, apply them to the database
This appears to be working fine so far. My only problem is integrating identity nicely. Currently I just have two contexts, my application one and an identity one. My application one has also mapped all the identity tables. It is working fine but I'm not sure what will happen going forward as I start linking tables to the user... I believe I did make it work with one context but I had to modify the generated application context each time, removing all the Identity mappings and inheriting from IdentityDbContext (to generate the identity mappings). I could change the schema of the identity tables/my tables and just generate the mappings for my tables, excluding the identity tables. Then I will probably need to manually write mapping properties on ApplicationUser, is that correct?
Basically, I'm not really feeling like Database First is a first class citizen in .NET anymore. Am I just missing something obvious to have this kind of just "work" without modifying generated code? Or am I overthinking this and just need to get on with it?
Apologies for the rambling, one of those days I guess.

How to execute seed step using migration.exe on existing database?

I have someone else's ASP.NET application that uses code-first EF and comes with the code for database migration and seed. I usually run migration.exe before the new version of the app gets installed and it worked well as long as I let EF do everything starting from creating a brand new database. Now I have to make it work against an existing and EMPTY database. When I run migration.exe it doesn't return any errors and perform all the required migration steps but it not longer runs seed step (it probably assumes it's not needed since the database already exists). How do I force running seed step in this case?
There are steps you need to ensure are set for your database initialization to achieve what you want:
CreateDatabaseIfNotExists: This is default initializer. As the name suggests, it will create the database if none exists as per the configuration. However, if you change the model class and then run the application with this initializer, then it will throw an exception.
DropCreateDatabaseIfModelChanges: This initializer drops an existing database and creates a new database, if your model classes (entity classes) have been changed. So you don't have to worry about maintaining your database schema, when your model classes change.
DropCreateDatabaseAlways: As the name suggests, this initializer drops an existing database every time you run the application, irrespective of whether your model classes have changed or not. This will be useful, when you want fresh database, every time you run the application, like while you are developing the application.
Custom DB Initializer: You can also create your own custom initializer, if any of the above doesn't satisfy your requirements or you want to do some other process that initializes the database using the above initializer.
The best help guide I followed with getting started on understanding Code first was written here and references the part you are referring to:
http://www.entityframeworktutorial.net/code-first/database-initialization-strategy-in-code-first.aspx
The important thing though is to know that you may want different things for different environments too and may wish to get into understanding how to do different deployments for different environments.
An example of a custom one would be like this:
public class EasyContext : DbContext
{
public EasyContext() : base("name=EasyEntity")
{
Database.SetInitializer<EasyContext>(new EasyInitializer());
}
public DbSet<Person> Person { get; set; }
}
You should be setting a breakpoint to make sure it is being caught or else you can force a new configuration to fire as well.

Entity Framework with existing database

I'm looking to implement entity framework version 4.3.1 in my existing project which don't follow this EF.The database is already developed and is currently used applying ado.net.In this case how do I start with to work on EF, is it Database First,Code first.
Even when a database already exists I still use the Code First approach, mapping the tables using annotations, because the domain is way more organized than on the EDMX file. If there are many tables the visual EDMX can become really useless since the design will be overcrowded with data and connections all over the place.
In two steps you can begin with this approach:
1) Create a domain model class, Customer for example, and map it to your table using data annotations:
[Table("tbl_cust")]
public class Customer
{
[Key]
[Column("cust_id")]
public int CustomerId { get; set; }
[Column("cust_name")]
public string Name { get; set; }
// Add other properties below
}
2) Create a context class deriving from DbContext and set DbSet<T> properties for each model, we have only one in our case so:
public class MyApplicationContext: DbContext
{
public MyApplicationContext() : base("name=ConnectionStringName") { }
public DbSet<Customer> Customers { get; set; }
}
Now anywhere in your code can instantiate the derived DbContext class and make queries using Linq:
var _db = new MyApplicationContext();
var customer = _db.Customers.Where(c => c.CustomerId == 37).FirstOrDefault();
Don't forget to add a reference to EntityFramework assembly using NuGet.
Good Luck.
Since your database already exists the obvious choice is Database first. If the database is designed with common sense it (mostly) works great.
I think the question is if you want to use the EF Designer to visualize your database or not. Since you are looking at EF 4.3.1 (in fact you should be looking at EF5 not 4.3.1 - EF5 is the latest version) I assume you don't care about the designer. In this case you could use EF Power Tools to reverse engineer your database. This will create a set of classes that will match your database. Note that since the database has already been created EF will not be able to detect changes in your classes (as opposed to databases created by Code First when additional information is stored in the database and EF is able to tell whether the model has changed). Make sure to read this blog post - it contains a lot of details you may find helpful to make the decision.
If you care about being able to see your model in the designer you can just use VS to reverse engineer DB. If you use VS2012 you will by default get EF5 and DBContext. The difference from using Code First will be that instead of building the model EF needs based on your classes the model is saved in the the edmx file that is part of your project (and used to generate code for you)

Entity Framework Automatic Migrations Existing Database

I am building an ASP.Net MVC4 web application with Entity Framework 5. I had to use an existing sql server database but also wanted to use Code First, so I followed this tutorial http://msdn.microsoft.com/en-us/data/jj200620.aspx
My application uses automatic migrations with Entity Framework.
The version of sql server I was using throughout the development phase was 2008, however, at the last minute I've been told the database needs to work on sql server 2005. I got the database I was using in sql server 2008 setup (exact tables, property names, relationships etc) on sql server 2005. However, with my web config etc setup to point to the sql server 2005 database, when I make a change to my one of my model classes, the automatic migrations don't work.
I get the following error
There is already an object named 'tblcourseprofessionTarget' in the
database.
Can anyone please help?
Thanks.
Apologies if I haven't added enough information.
Folks
The answer to my problem above was helped by this article http://christesene.com/entity-framework-4-3-code-first-with-automatic-migrations/
I had to delete my previous initial migration class, and re-create it.
I had a similar problem.
The cause for me was that the same migration had been run already in the database but under a different MigrationID. I had 201504302005411_InitialCreate but my migration script was called 201505041911076_InitialCreate.
I fixed the issue by renaming the MigrationID in the database to match the one in my code.
I don't quite know how I ended up in the situation but renaming the MigrationID meant the app knew the script had already been run.
if your context is mine: added a new entity class worked on it but, when I tried to migrate it shows this error, try removing that object from db context then run update-database and add that object again and rerun update-database
for example:
public DbSet<CustomizedEmail> CustomizedEmail { get; set; }
public DbSet<KeyWordsForEmail> KeyWordsForEmail { get; set; }
public DbSet<Notice> Notice { get; set; }//remove it>run update-database>
//add again the above entity and rerurn update-database
this works whether you have data or not. in this process you will loose data in that table.

Can't enable Migrations in Entity Framework 4.3

I have a class library with EF Code First. I just upgraded to EF 4.3 and now I want to enable migrations.
I type Enable-Migrations -ProjectName MyProjectName in the PM console but receive the following error
PM> Enable-Migrations -ProjectName MyProjectName
System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
at System.Data.Entity.Migrations.DbMigrationsConfiguration.GetSqlGenerator(String providerInvariantName)
at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration, DbContext usersContext)
at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration)
at System.Data.Entity.Migrations.Design.MigrationScaffolder..ctor(DbMigrationsConfiguration migrationsConfiguration)
at System.Data.Entity.Migrations.Design.ToolingFacade.ScaffoldRunner.RunCore()
at System.Data.Entity.Migrations.Design.ToolingFacade.BaseRunner.Run()
The given key was not present in the dictionary.
PM>
I cant figure out what dictionary that might be wrong.
My connection string looks like this:
<connectionStrings>
<add name="MySystem" connectionString="Data Source=MyServer\Instance;Initial Catalog=myDbName;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>
Any idea about what might be wrong?
Just a note:
I use my class library in a console application with an exact copy of my app.config and there I can access my database perfectly well.
It turned out Anders Abel was right in the cause, but we found a much simpler solution.
According to the mvc-mini-profiler page there is a special package in Nuget called MiniProfiler.EF that does not requires any wrapper around the SqlConnection. We dropped our old mvc-mini-profiler and installed the MiniProfiler.EF. Then Enable-Migrations worked as expected.
EF Code First has an extensible provider model for Sql code generation. The documentation for DbMigrationsConfiguration.GetSqlGenerator says what it does:
Gets the SQL generator that is set to be used with a given database
provider.
The MvcMiniProfiler wraps itself around the DB provider to add profiling support. To EF it will look like you're using a MvcMiniProfiler DB and not a MSSQL DB. Unfortunately EF Code first doesn't know how to handle a MvcMiniProfiler DB.
A possible fix would be to add a SqlGenerator with the MvcMiniProfiler name that wraps the Sql Server generator.
Edit
Looks like it might be possible to just reregister the existing sql server generator for the mvc mini profiler name (if you figure out the name of it).
At http://romiller.com/2012/01/16/customizing-code-first-migrations-provider/ there is code snippet that shows how to register a provider:
public Configuration()
{
AutomaticMigrationsEnabled = false;
SetSqlGenerator("System.Data.SqlClient",
new CustomMigrationsProviders.CustomSqlServerMigrationSqlGenerator());
}
This may be a related, but different problem, but since it was Anders' post here that lead me to the solution, I figured I post this solution here as well.
The Problem:
If MiniProfiler is initialized before our Entity Framework database initialization strategies execute, the initialization fails with an error about a missing migration table.
If the Entity Framework database initialization strategies execute first, access to entities fails with a type casting exception as the MiniProfiler DbConnection is tried to be forced into a SqlConnection variable (in an internal generic).
The Cause:
When MiniProfiler initializes, it uses reflection to retrieve a collection of database providers from a private static field in System.Data.Common.DbProviderFactories. It then rewrites this list with MiniProfiler shim providers to replace the native providers. This allows MiniProfiler to intercept any calls to the database silently.
When Entity Framework initializes, it starts to compile the data models and create cached initialized databases stored in System.Data.Entity.Internal.LazyInternalContext inside some private static fields. Once these are created, queries against the DbContext use the cached models and databases which are internally typed to use the providers that existed at initialization time.
When the Entity Framework database initialization strategy runs, it needs access to the bare, native Sql provider, not the MiniProfiler shim, in order to correctly generate the SQL to create tables. But once these calls to the native provider are made, the native provider is cached into LazyInternalContext and we can no longer inject the MiniProfiler shims without runtime failures.
My Solution:
Access the private collections inside System.Data.Entity.Internal.LazyInternalContext and clear out the cached compiled models and initialized databases.
If I perform this purge between the operation of the EF database initialization strategies and the initialization of MiniProfiler, the MiniProfiler shims can then be inserted without causing later runtime failures.
Code:
This code did the trick for me:
Type type = typeof(DbContext).Assembly.GetType("System.Data.Entity.Internal.LazyInternalContext");
object concurrentDictionary = (type.GetField("InitializedDatabases", BindingFlags.NonPublic | BindingFlags.Static)).GetValue(null);
var initializedDatabaseCache = (IDictionary)concurrentDictionary;
if (initializedDatabaseCache != null) initializedDatabaseCache.Clear();
object concurrentDictionary2 = (type.GetField("CachedModels", BindingFlags.NonPublic | BindingFlags.Static)).GetValue(null);
var modelsCache = (IDictionary)concurrentDictionary2;
if (modelsCache != null) modelsCache.Clear();
Warning:
It appears that the names of the internal fields in LazyInternalContext change between versions of EF, so you may need to modify this code to work with the exact version of EF that you include in your project.