Code First Migrations for dynamically assembled model - entity-framework

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

Related

Is there a way to query the database before or during OnModelCreating?

Inside of OnModelCreating, I want to be able to ignore a column if the database is on an older migration EF Core 5 throws an exception if I attempt to read from the database directly, or indirectly by querying the applied migrations. I'm not certian that it's even a good idea, since OnModelCreating is used during the migration 😩, but I'll burn that bridge when I cross it.
There are some examples on how one would do this with EF6, but they don't seem to apply anymore with EF Core.
While Ivan Stoev is right that --generally-- you should model the target database without outside input, the real world isn't always that clear-cut. In my particular case, there are multiple service instances (Azure Functions) that need to read and write to a single database. In order to maintain zero downtime, those Functions need to not read or write columns that don't yet exist.
I solved the problem the way Serge suggested. The database has a known version, populated with seed data that increments with every migration. On startup, the service reads that version with a regular old Microsoft.Data.Sql.SqlConnection. This version is then added to the IServiceCollection as a singleton to be used by the DbContext constructor.
When talking to an older database version, OnModelCreating does things like this:
builder.Entity<Widget>(w =>
{
// another option would be to use the migrations table instead of an integer
if (DatabaseVersion < ContextVersions.WidgetNewPropertyAddedVersion)
{
w.Ignore(w => w.NewProperty);
}
else
{
w.Property(w => w.NewProperty)
.HasDefaultValue(0);
}
});
The startup code also detects if it's been started by the Entity Framework tools and does not read the database version, instead assuming "latest". This way, we do not ignore new properties when building the migration.
Figuring out how to let the service instances know that the database has been upgraded and they should restart to get the new database model is an exercise left up to the reader. :)

How do I ensure a table exists in EF Core without using migrations?

I'm writing a quick prototype project. I don't want to use EF migrations because I don't really understand them yet. The app imports data from a file into a DB. If the schema changes, my strategy will be "drop the tables and let EF rebuild them".
This works OK for adding data at startup, but I had trouble deciding if I needed to build the DB. For example:
var inputCount = parsedData.Items.Length;
var dbCount = _itemsContext.Items.Count();
if (inputCount != dbCount)
{
// Do updates/inserts
}
Since the table doesn't exist, I can't query for a count. I could handle the exception but that felt a little messy. I just needed EF to create the table if it's not there. Everything I read walked me through adding migrations to the project but it feels like a feature I didn't want.
(I couldn't find a clear duplicate of this with the questions my use case generated. Now that I know the answer I can find questions that discuss it, but I hope this post helps guide someone that way.)
The DbContext type has a Database property that gives you sort of backdoor access to things EF manages. It has a convenience method EnsureCreated (also an async implementation) that will ensure the table exists when the DbContext is configured.
Credit to this EF tutorial for explaining this and a handful of other exotic initializaton scenarios.o
Based on some other things I've read it seems this makes adding migrations later impossible, and perhaps Database.Migrate() does the same thing more safely. So have an idea whether you want migrations at all before you do this (but if you plan on using migrations, it seems silly to be doing manual initializations?)

Changing Entity Framework Entity Class Without Changing Schema

I have an application already in production using EF 5.0. I'm about to start on the next major revision. But before I do that, I'm trying to clean up a lot of my existing code.
One thing I want to change, is use a different class for one of my table entities. The new class is functionally identical to the previous. The only real difference is the name. E.g. ReceiptEntity will become Receipt.
This is to help simplify things, and stick to a simple naming convention.
However, EF Migrations are wanting to drop-recreate the table. This is not an option because the application is already in production. And I cannot allow for any data-loss.
Is there any way to change the Entity type without recreating the table that would make EF happy?
I was able to fix this by altering the generated migration.
The generated migration tried to create a table(one that already existed), then immediately drop it(which would of resulted in the data-loss).
I deleted all of the generated code, and simply 'Update-Database'ed an empty migration, and this solved the problem for me.

Entity Framework code first - development strategies

Working on a brand new project from the ground up. That means the data model is in a constant flux, doubly so because things are, inevitably, not as well planned as they should be. Model classes are being created and changed fairly regularly.
The plan was to use the latest version of EF with all the neat code-first stuff in it. But we're constantly tripping over the limitations the framework has in terms of adding or updating tables. The initialization options seem to allow only the complete deletion and re-creation of the database, which isn't really ideal.
I've had a look at the migrations. But this seems a sledgehammer to crack a nut: we don't need to detail every single small change and update with a new migration scaffold.
Are there some better strategies to deal with this? For instance, I started writing some unit tests to pre-populate one of the contexts with some test data, but because this causes the whole Db to drop and re-create, it causes problems with all the other contexts. Or perhaps making use of a custom initialiser to seed the data for us? How can we easily exclude these in production code?
We're also wondering about perhaps abandoning code-first and going back to EDMX diagrams. At least that way changes result in updated SQL commands which can be run directly against the database.
Any suggestions gratefully received.
I think, imho, that:
as the database schema must at least match your model you should/must detail every single change, and code first migration allows that and trace the changes over time
code first migration also allows to migrate the database schema for you
code first migration also allows you to produce sql that allows you to migrate the schema
For these reasons code first is as good (if not better) as the edmx approach
Please take few minutes to implement http://msdn.microsoft.com/en-us/data/jj591621.aspx
One other point, always imho and in a perfect world, if you unit test the business of you model you should not need the DAL, use generic collection. Be aware of different comportement of linq to object vs linq to entities, for example concerning the case sensitivity.

Entity Framework Code First with an existing database

I have to create a new project and (as usual) is with an existing SQL Server database.
I used to use EF Code First connecting with my database, opening my EDMX model designer and then right click --> Add Code Generation Item. (http://weblogs.asp.net/jgalloway/archive/2011/02/24/generating-ef-code-first-model-classes-from-an-existing-database.aspx) Easy.
But now I've discovered there's something called EF Power Tools that allows me to do Reverse Engineer Code First (cool name!) and get the same (http://msdn.microsoft.com/en-us/data/jj200620)
Do you know the difference between the two options? Which one is better?
Thanks in advance.
(Sorry if this question was previously asked but I didn't find it.)
The difference is that the edmx approach is not code first, but database first with DbContext API. You will always use the database as the source of model changes.
EF Power Tools produce a truly code first model with DbContext: from then on you will change the class model first and modify the database accordingly (e.g. by EF migrations).
Neither is "better". DbContext API is easier to work with than ObjectContext, but both approaches use the former. It's up to you to choose whether you want to work database first or code first. It's a matter of personal preference and it may depend on who maintains the database structure. With database first it is easier to respond to changes someone else imposes on the database structure.
As far as workflow goes for database first, adding to what #Gert-Arnold said:
With database first it is easier to respond to changes someone else imposes on the database structure.
If someone else is managing the database changes, I'm finding it far easier to use the EF Designer. You get an updated database, then just right-click in the EF Designer and update the model from the database. You can use source control to easily view what has changed.
Also, if you only need a subset of tables from the database, reverse engineering causes alot of work having to go back and remove classes and properties from the context.
I found re-reverse engineering via code-first to an existing database to be just too much of a pain trying to figure out what changed and how I needed to update code that used the context.