How do I tell EntityFramework Migrations to use the connection used by the current context? - entity-framework

When I create my context using a connection string name, that connection is used as expected, but not by the code running Migrations!
That code creates a new context with the parameter-less constructor which then obviously uses its default connection resolving mechanism and thus connects to a different database!!
This seems very undesirable default behavior to me. Why does Migrations not use the current context, or at least the same connection string as the current context?
Am I missing something or is this a flaw in Code First Migrations? And what is the best way to work around this? Implementing IDbContextFactory? Or do somting with Database.SetInitializer in the context constructor?
I actually ended up querying my database without any exceptions occurring (since I did not run any code relying on the migration), and at the same time secretively creating a completely new database in SQLEXPRESS.
Version used is Entity Framework 6 with .NET 4
To prove my findings I added some screenprints from the debugger. The first one shows that the connection taken from connection-string SiteSqlServer is actually used. The second one shows that the connection used in the database initialization code is different.
The third shows the stacktrace at the time of the screenprints.
(Hopfully the prints are readable, zooming in helps)

Related

Strategy for deploying EF controlled Database

I have written an application using EF 6.0 in combination with an SQL Server Compact 4.0 Database. When a customer uses this application for the first time, it (the application) should create a database-file in a given path with some initital values. Also migrations should be allowed, for it is quite possible that the object model might change with future versions of the app.
Now I´m wondering what would be the best way to to deploy the DB on the users productive system. I could think of three ways:
I could create a DB-file with initial values and just copy it to the right place during installation process and use MigrateDatabaseToLatestVersionInitializer in the app.
In the DbContext-Constructors (I have two contexts) I could check for an existing DB-file and use different Database-Initializers accordingly. Like a CreateDatabaseIfNotExistsInitializer with a seed method that creates initial data if no fiel is found and a MigrateDatabaseToLatestVersionInitializer if the DB-file exists.
I could use the MigrateDatabaseToLatestVersionInitializer always and in its "Seed"-method check for existing table entries and create them if they are not present.
Which of these ways is to be preferred or is there a better way I didn´t think of?
It sounds like this is a desktop application so you might want to catch permissions errors about creating the database file at installation time (i.e. option 1) rather than run time, especially as in option 2 the database initialization is not an imperative command you're giving that you can put a try...catch around.
I don't think option 3 would work as the Seed method gets run after all the migrations, so surely the migrations will either have successfully run, in which case the tables don't need creating, or they will have failed as the DB doesn't exist and therefore your Seed method won't get run.

Odd failure to create SQL Server CE .sdf file in LINQPad query

I'm using LINQPad with a custom assembly, behind which there is an SQL Server CE database which may or may not exist at the time. The custom assembly uses Entity Framework code-first with automatic migrations, and includes a simple initialiser inheriting from MigrateDatabaseToLatestVersion which will create the database if it doesn't exist. I've been working with it for a couple of weeks and it's been working quite nicely.
This morning, after a small glitch proved frustratingly difficult to diagnose until I realised that a migration had happened between two events in the log, I decided it'd be nice if the database's own log table noted when a migration had been applied. To that end, I added a couple of lines to the Seed() method in the initialiser to instantiate the generic repository/unit-of-work container I've been using, add a record to the logs table, and commit the changes back to the database. The repo has a flag to indicate that it does not own the underlying context, so I can be sure that it doesn't dispose the context I'm then going to try to use.
Now, if I change the model (I'm testing by repeatedly commenting and un-commenting one of the DbSet properties on the context class) then a record is inserted to note that a migration took place. Exactly what I wanted. However, if the .sdf file doesn't exist, LINQPad gives me the following error:
The underlying provider failed on Open
InnerException: The database file cannot be found. Check the path to the database.
While the error message is perfectly self-explanatory (the file can't be found because it isn't there) what isn't clear is why it doesn't just create the file like it did before. What's really odd about this is that if I re-compile the custom assembly and then run the LINQPad query again, then LINQPad will create the .sdf and continue happily. This happens even when the changes to the assembly are irrelevant. In testing, I have run the query, watched it fail, then added a single blank space to the end of a comment in the repository class, re-compiled it, and then run the query again... and it worked. I am completely at a loss to explain how that should have made a difference.
At this point it may be worth mentioning that the "custom assembly" I'm dealing with here is LINQPad's own "My Extensions" file. Yes, I wrote a data context with code-first automatic migrations initialisation and a generic specification-pattern transactional repository in my extensions file. Yes, I realise that's probably not what it's meant for. I was bored, and wanted to test something. Anyways, this may be causing something strange somewhere. It may not, but I thought I'd mention it just in case.

EnterpriseLibrary, EF, and Transaction Scope: why am I seeing different behavior?

I have one app that uses EnterpriseLibrary and Unity, and uses TransactionScope in just one place. This works nicely, despite the fact that it runs against SQL Server 2005:
// Execute a stored proc using a DbDatabase object inserted by Unity
using(TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
{
// Update something using the same DbDatabase object
// Run the stored proc above, again
// Assert that the results are different than from the previous call.
}
Yes, this deliberately ends without a scope.Complete(): the example is from a test.
I also have another application just beginning. It uses Entity Framework 4.1. It accesses the same database on the same server. I attempted to use TransactionScope, with the same "make change, verify change, roll back change" idea in mind.
using(TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
{
using(ProjectEntities db = new ProjectEntities())
{
Assert.IsFalse(db.tblEntities.Any(e=>e.X == desired_value));
db.tblEntities.Add(new tblEntity() { X = desired_value });
db.SaveChanges();
Assert.IsTrue(db.tblEntities.Any(e=> e.X == desired_value));
}
}
This fails with the very familiar error about MSDTC not being enabled for network access.
Right now, this minute, the first test in the first project succeeds, the second test fails.
So I have two questions:
Is there a way to rejigger my second test that would keep the transaction from escalating to MSDTC?
Anybody know why I'm getting different results from the two frameworks? Does EntLib keep a single connection allocated and open during the whole time it's used? Does EF do the opposite?
I have made many test regarding EF, EntLib DAAB, and TransactionScope.
There are several points you must take into account.
SQL Server Version
Connection String
EF and EntLib version
I don't remember the other combinations, but with SQL Server 2008 or later, EF5, and Entlib 5, you can enroll several DbContexts and DAAB operations in the same TransactionScope without scalating to MSDTC. But there's a very tricky part:
the connection string must include: MultipleActiveResultSets=true;
the connection string must have the exact format used by EF
The second part is the most confusing: when you use a connection string to EF, it will chaneg its format, but EntLib uses it as is in the connection string of the config file. So, what you have to do is debug the code, and note down the modified version of the connection string used by EF. You can find it in ctx.Database.Connection.ConnectionString, where ctx is the DbContext you're using. Once you've done so, just copy and paste the modified version of your connection string to your config file, and both EF and EntLib will use the same connection string, thus not escalating to MSDTC.
For previous versions of SQL Server (and sometimes depending on EF version) you can find different problems, but this guidelines can help you test your exact setup.
I don't know about the EnterpriseLibrary but EF does create and open new connection for every query and I think this is why you see those different results.
You can verify this by opening two DbConnections by hand.

Code First Migrations for dynamically assembled model

My database model (sometimes referred to as "context") is dynamically assembled at startup based on which services and/or plugins are installed. Plugins and services export their model definition fragments through my IoC container and the application core picks them up and runs them when the DbContext.OnModelCreating method is called.
The question is: Can I (and how do I) use Code First Migrations with this setup?
(below is more information on what I've tried and what particular problems are)
In my previous project, the database was inherited from some old code so we couldn't use any of the Code First database generation stuff anyway. We simply kept a long line of delta scripts and executed them manually on deploy (it was a single-host kind of project).
Now I'm starting a new project, and this time, the database is brand new, ready for Code First to play with. Initially, I was all excited about Code First Migrations, seemed like the way to go. Until I actually tried it. The initial attempt, quite obviously, failed due to the absence of an explicitly defined DbContext in my project.
So far, it looks like the only viable option is to manually code migrations, with which I am perfectly fine. However, it turns out that this is not as simple as just creating a few classes inherited from DbMigration.
After some experimentation on a small test project, I was able to find out that the migration autogenerator adds an implementation of IMigrationMetadata, which, among other things, contains a hash of my model as the values of the Source and Target properties. Presumably, this hash is then used to identify a path across migrations from the "current" state of the database (as recorded in the __MigrationHistory table) to the newest state as defined by the model in code. This totally makes sense, but...
Naturally, I have no idea where to get that hash for my model, which makes me unable to implement IMigrationMetadata on my migrations.
On the other hand, I see that the metadata interface is not included in the DbMigration class itself, which makes me think that it might be optional. It then follows that migrations can actually work without the hash values, but the question is - how?
All the information I could find on the internet is just simple, very basic tutorials. No information on how to create migrations manually (and whether it's even supported). No documentation on how it actually works and how to extend it. And it is not quite obvious from outside.
I am ready to resort to ILSpy at this point, but the whole EF is so complex that I fear I may not be able to find what I need in reasonable time.
Here are a few ideas that you could pull together to find a solution that works for you. I realize I mentioned some of these in our other thread, but I'm including them here for others reading this question.
Automatic migrations allow Code First to automatically calculate and apply changes to the database.
You can write your own code to generate and apply migrations. I've written a post about applying migrations and the MigrationsScaffolder class will help you create migrations.
When you run the project , an extra table is created in the database.
EdmMetadata table
The hash is always created with the help of EdmMetadata Entity and the current code first model. It is SHA-256 hash stored in the EdmMetadata table of the database. You can get it from that table.
Methodology to be followed will be:
Get the hash of the current model using
var hash=GetModelHash(OldContext);
Check whether the model in the code (new model) is compatible with the model in database(old model) using
CompatibleWithModel(hash,CurrentContext,ObjectContext)
This method returns bool.
If it is not compatible, then delete the existing tables in the database.
Create new tables
Save the current hash to the databse
Seed the data.
The code may look like:
{
var objectContext = ((IObjectContextAdapter)context).ObjectContext;
var modelHash = GetModelHash(objectContext);
if (CompatibleWithModel(modelHash, context, objectContext))
return;
DeleteExistingTables(objectContext);
CreateTables(objectContext);
SaveModelHashToDatabase(context, modelHash, objectContext);
SeedData(context);
}
Be sure to make the class inherited from
IDatabaseInitializer<T> where T:DbContext

EF usage from thread spawned from Role.OnStart()

I'm using EF code-first to manage my DB connection, with an explicit connection string declared in web.config. I would like to schedule some DB cleaning process (like deleting test transactions every day), so I'm spawning a thread from Role.OnStart() with proper concurrency management among the instances.
But I'm getting DB database exceptions, like the DB not matching my model, whereas I'm sure it does (the same code used from "inside" the app works well). So my guess is that web.config is not used from the thread, so EF probably uses the default connection string.
What would be the best way to use my connection string from there ?
Thanks
The OnStart method doesn't run in the same process as your web application meaning it doesn't make use of the web.config. I suggest you store the connection string in the service configuration and read it from here when initializing your context.
An other advantage is that you change the setting without re-deploying the application.