Can't enable Migrations in Entity Framework 4.3 - entity-framework

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.

Related

Entity Framework Core 2.0 Dynamically Creating A Database

I am new to EF Core, and as I tried using it I found out that you need to add migrations for it to create a database from models. My question is, do we have another option aside from migrations to dynamically create the database on run time just like what it was in EF 6?
Thanks.
Until a seeding mechanism is provided in EF Core you can provide your own seeding mechanism.
In earlier phases of a project, when the database is not yet fixed, I don't care that data get lost. When I want to recreate the database dynamically I call the function below. By the setting of a parameter I determine if this "recreateDatabase"-function is called yes or no. The function is included in MyOwnDbContext class.
The seed function you need to write is very similar to the one you use in EF 6.
private static void recreateDatabase(YourOwnDbContext dbContext)
{
dbContext.Database.EnsureDeleted();
dbContext.Database.EnsureCreated();
seed(dbContext);
}

Entity Framework not returns data

I'm using EntityFramework 6.1.3. I have generated models from an existing database. Now, when trying to query the database, datacontext returns null. The database appears to be empty.
But the database is not empty as I can connect and query it using LINQPad. When googling the problem I came across a similar situation. In that case the EF generated an empty database on the local server and the solution was to tweak the connection string, although without clear details what exactly should be changed.
However, I'm not sure if that is the case in my situation.
My connection string is pointing to the remote server.
It is not possible that the database was created on the remote server, as we don't have authorisation.
The database was not created on my local machine as I dont even have local sql server installed. And my AppData folder is empty.
Any suggestions?
Generated connection string below
<add name="MAST_DEV" connectionString="metadata=res://*/Models.Mast_DevModel.csdl|res://*/Models.Mast_DevModel.ssdl|res://*/Models.Mast_DevModel.msl;provider=System.Data.SqlClient;provider connection string="data source=xxxxxx;initial catalog=MASTER_DEV;user id=xxxxx;password=xxxxxx;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
I don't really know what I was doing wrong. I have created simple project from scratch , generated models again and it does work fine now. Possibly, previously I selected 'Code first from the database' from Entity Data Model Wizard. Whereas this time 'EF Designer from the database'. Anyway, thanks for trying to help. It was my mistake
This is the exact solution for my problem (the answer is copied from here Entity Framework cant use the DbContext, model being created)
"I see you are using the EDMX with Templates (.tt) for generating the classes. But if you are getting the information from a existing database, the wizard will create a ConnectionString compatible with ObjectContext (metadata informations and provider of entityframework).
The problem is that the connectionstring you are using is for ObjectContext (Database First and Model First). For the DbContext you should use the connectionstring without the metadata informations"

Accessing DB2-LUW 10 with entity framework 6

I am developing an application in which the database is selected by the end user at runtime. The database can either be on a MS SQL server or an IBM DB2 server. I am currently using IBM DB2 10 Express-c on a windows server for testing. I am developing using Visual Studio 2013 C# and Entity Framework 6. I have installed the EntityFramework.IBM.DB2 Nuget package for the DB2 support. I am using reverse-engineer code-first against an existing SQL server database to generate my base code. The application works fine against a SQL Server database.
I am using System.Data.Common.DbProviderFactories.GetFactory to generate the provider.
System.Data.EntityClient.EntityConnectionStringBuilder connectString = new System.Data.EntityClient.EntityConnectionStringBuilder(a_Connection);
System.Data.Common.DbConnection conn = System.Data.Common.DbProviderFactories.GetFactory(connectString.Provider).CreateConnection();
conn.ConnectionString = connectString.ProviderConnectionString;
LB500Database = new LB402_TestContext(conn, true);
a_Connection is provider=IBM.Data.DB2;provider connection string="Database=LISTBILL;User ID=xxxx;Password=yyyy;Server=db210:50000"
and is being parsed correctly by the EntityConnectionStringBuilder.
I then try to access a table in the database with
LBData500.LB_System oneSystem;
System.Linq.IQueryable<LB_System> allSystem = LB500Database.LB_System.Where(g => g.DatabaseVersion == databaseVersion && g.CompanyID == companyID);
I get an invalid operation exception "Sequence contains no matching element" which means that no elements are returned. If I remove the Where so that all rows are returned (there is one in the table) and try to enumerate the result set using the VS debugger I see the message:
"The context cannot be used while the model is being created. This exception may be thrown if the context is used inside the OnModelCreating method or if the same context instance is accessed by multiple threads concurrently. Note that instance members of DbContext and related classes are not guaranteed to be thread safe."
I am not using multi-threading. I am not inside the OnModelCreating.
Just changing the connect string to point to SQL server works fine, so I think my basic approach is sound. If I were getting some kind of error back from the server I would have something to go on. I can run the query from inside Visual Studio, so I have connectivity.
Any pointers would be appreciated.
UPDATE:
I turns out the EF objects were generated using EF5 and the EF6 runtime was being used. I regenerated the EF objects using EF6 reverse engineer code first. I can now connect to the database and get an error message:
"ERROR [42704] [IBM][DB2/NT64] SQL0204N \"DBO.LB_SYSTEM\" is an undefined name."
The schema in the DB2 database is the same as my userid (in this case, not always). I added the CurrentSchema=xxxx to the provide connection string, but EF is still passing dbo as the schema name.
Now I need a way to change the schema name at run time. I saw a link to codeplex EFModelAdapter (http://efmodeladapter.codeplex.com). So I may give that a try.
Update2 After looking through EFModelAdapter, I decided to take a different route. Since I only need database access and not schema management, I decided to go with Dapper (https://github.com/StackExchange/dapper-dot-net). This works great for what I need and allows me to change the schema name when accessing DB2 databases.
As per my Update 2, Entity Framework was a little overkill for what I needed. I switched to dapper https://github.com/StackExchange/dapper-dot-net and I am working fine against multiple DBMSs.

entity framework error there is already an object with that name available in the database

I am using the Entity Framework POCOs to assist with migrating data from a legacy database to a new database. Both databases already exist and the Entity Framework has no part in creating or modifying structure for either. I created a sample database on the migration server and restored it to my local computer sql server (entirely in t_sql, no EF) and my context and its data classes are working fine and returning the data I want. Today I went to the production migration server and when I go to run my first test I get the above referenced error.
All I am doing is reading data, no writing, so this makes no sense to me. EF must be doing something when it hooks up the data context that I can't see. The error is coming from SqlClient.SqlConnection. There is no inner exception, no help link and nothing in the call stack except my method
Any ideas where to start looking?
Pamela
So it turns out the Entity Framework gets mad when the database changes at any point. You need to tell it to ignore the database. I did it by creating this base class for my data contexts
enter code here public class BaseContext<TContext> : DbContext where TContext : DbContext
{
protected BaseContext()
: base("Foxpert.HS.ChangeDetection.VHSContext")
{
Database.SetInitializer<TContext>(null);
Configuration.AutoDetectChangesEnabled = false;
}
}

Code First for SQL Server 2005?

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.