Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Entity Framework code-first with a newer database model version

Maybe an odd question, but we have a scenario in which we want to use Entity Framework code-first in an environment which could have a database with a newer/higher version than the code itself.

Let me elaborate a bit. We have a couple of solutions which all use a core assembly which contains the overall datamodel which all solutions are using. The solutions are mainly sites and apps which are deployed to several different Azure Web Sites. So the solution are running next to each other. The only thing they are sharing is the Azure database.

Now the scenario will come in play. When we update the database model in the core assembly and update one of the solutions in Azure. The underlying database will be updated when the model is loaded within that solution. No problem there, works like a charm...

The problem starts when one of the other solutions is loaded. These other solution are still using the previous core assembly which has now an outdated EF CF model compared to the database model they are connecting with. So a nice exception will be throw as shown below.

The model backing the '{NAME}' context has changed since the database was created. Either manually delete/update the database, or call Database.SetInitializer with an IDatabaseInitializer instance. For example, the DropCreateDatabaseIfModelChanges strategy will automatically delete and recreate the database, and optionally seed it with new data.

The question is whether we can force the model just to load and ignore the changes made within the database. We internally have a policy to only apply not breaking changes within the database, so the model should be able to load without any problems.

Thanks in advance for the information and tips!

like image 979
Sander Avatar asked Sep 26 '22 21:09

Sander


2 Answers

I can be wrong(not sure whether I remember correctly), but if it doesn't interferes with your application configuration, you can set DB initializer to null:

    public PortalDbContext()
        : base("name=PortalConnectionString")
    {
        Database.SetInitializer<PortalDbContext>(null);
    }

Or it could be possible to create custom initializer:

public class BlogContextCustomInitializer : IDatabaseInitializer<BlogContext>
{
    public void InitializeDatabase(BlogContext context)
    {
        if (context.Database.Exists())
        {
            if (!context.Database.CompatibleWithModel(true))
            {
                // Do something...
            }
        }
    }
}
like image 121
kamil-mrzyglod Avatar answered Sep 30 '22 08:09

kamil-mrzyglod


If you're using EF Code-First, the model must match the database.

Even if you found a way to circumvent that limitation you'd be doing something dangerous.

Let me expalin it: if you update the database from "Solution A", the model in "A" will match the database, and any further changes to the model in this solution can be applied to the database without any problem at all. That's right!. However, if you do what you're asking in this question, i.e. you do something so that "Solution B" can keep working even if the model doesn't mathc with the DB, and then you make a change to the model in "Solution B", how do you apply it? how can "Solution B" know what changes to apply? how can "B" determine what changes made by "A" should be left as they are, and what are the new changes made by "B" that must be applied to the database?

If you could follow on like this, you'd finish with two different code first models, none of which matches the database, and, besides, how could you warranty that both applications work correctly? how can you ensure that changes on "A" doesn't affect code on "B" and viceversa?

The safest solution to avoid this problem is to share the assembly containing the code first model between both solutions. Any other solution will be troublesome sooner or later. Perhaps you'll have to refactor your solutions so that they can share the same DbContext. The DbContext must be the only thing in your project. I usually have an Entities project, and a DbContext project which has a reference to Entities. Then both solutions would have references to these projects. These projects can be in one of the solutions, or in a completely different solution. Of course in one, or both solutions, you'll have to add a reference to the DbContext assembly, instead of the project, and keep it updated, for which you can use post-build scripts. In this way, when you recompile your solutions you'll also detect incompatible changes made for one solution which adversely affects the other.

EF6 supports several different DbContexts in the same database, so, if each of your applications had a different, non conflicting DbContext, you wouldn't have a problem. I cannot check it right know, but I think that the name of the DbContext must be different in each solution (I don't remember if the namespaces are taken into account). By non conflicting I mean that they refer to different database objects (tables, views, or whichever), of that the objects refered to by both contexts are not changed (for example master tables).

like image 39
JotaBe Avatar answered Sep 30 '22 08:09

JotaBe