数据库
首页 > 数据库> > c#-使桌面客户端可以在不更新的情况下使用新的EF数据库迁移

c#-使桌面客户端可以在不更新的情况下使用新的EF数据库迁移

作者:互联网

目前,我有一个ERP,它是一个基于Winforms的客户端(带有SQL Server),可以使用ClickOnce在桌面上交付和更新它.

当前版本正在使用Entity Framework 4(基于ObjectContext)和数据库.当数据库架构发生更改时,我对客户端进行更新的方式分为四个步骤:

>在生产中创建具有兼容列的中间更新数据库模式(允许在所有位置为null或具有默认值,等等).旧客户端可以连接到该数据库并继续工作,就好像什么都没有改变一样
>将桌面客户端更新为具有更新功能的中间版本,该更新功能说明了此中间架构,但具有所有“最终架构”功能
>一旦所有客户端都更新并且所有记录都与“最终”模式兼容,请使用所需的数据库约束对该模式进行新的更新
>将所有客户端更新到映射到该最终模式的最终版本(这解决了数据库约束错误,并且需要那些模式更改才能起作用).

我发现这个过程对我们来说比较麻烦,对客户来说比较好,他们可以在他们认为合适的时候进行更新,并且在工作中不会被更新打扰(可能涉及到拥有客户)在不想等待软件更新的人面前).

现在,我使用EF6和代码优先的迁移对客户端(仍然是Winforms)进行了几乎完全的重写.

我一直在寻找文档,但找不到任何东西(似乎这些天只有Web编程,通常可以同时完成数据库和Web客户端的更新,而不会中断用户),但是一旦我将迁移应用于生产,未更新的客户端将无法再使用该数据库.如果不是最新的数据库架构,EF将在实例化上下文时进行投诉并引发异常.

一个具体的问题:是否有一种方法可以使EF6代码优先的dbcontext与兼容的内置数据库一起用于较新的数据库模式迁移?如果是这样,我可以继续做我到目前为止所做的事情.

还有一个(我猜)基于oppion的问题,是否有人想扩展实际答案:是否有更好的方法来处理这种情况?我敢肯定我不是唯一一个遇到此问题的人,但是Google所需的文档关键字太广泛了,到目前为止,我的搜索只涉及到Web场景.

我目前正处于客户端重写的一个阶段,在该阶段可以进行重大更改,所以我不在乎该解决方案是否会使部分代码复杂化

解决方法:

当应用程序初始化模型数据库时,通过直接调用DbContext.Database.Initialize或实例化第一个DbContext,它会检查应用程序中的模型与数据库中的模型是否匹配.

为此,它将计算模型哈希,并将其与__MigrationHistory表(或如果从EF 4.x更新的,则为EdmMetadata表)中存储的哈希进行比较.这是在System.Data.Entity.Internal.ModelCompatibilityChecker.CompatibleWithModel方法中完成的,该方法接收一个名为throwIfNoMetadata的参数,该参数在内部实现中恰好为false,因此,如果没有元数据,则不会引发任何异常.

因此,如果您在初始化数据库之前以某种方式使该表消失,则可以避免该错误.重要的一点是,您必须在不使用DbContext的情况下进行此更改.如果没有,数据库将尝试初始化,并且如果该表存在,它将失败.因此,您可以使用普通的ADO.NET删除表.

考虑到元数据表可以自动创建,例如通过应用迁移.

您还可以使用ctx.Database.CompatibleWithModel(true)来检查数据库元数据是否存在以及是否兼容,以摆脱它.该参数正是我上面提到的throwIfNoMetadata.

db初始化程序中的兼容性检查:

默认的数据库初始化器是CreateDatabaseIfNotExists,并且它会在throwIfNoMetadata设置为false的情况下检查模型的兼容性.这就是为什么该解决方案有效的原因.但是,如果您实现自己的版本的DB Initializer,但该版本不会运行检查,则它将起作用.

public virtual void InitializeDatabase(TContext context)
{
    Check.NotNull(context, "context");

    var existence = new DatabaseTableChecker().AnyModelTableExists(context.InternalContext);

    if (existence == DatabaseExistenceState.Exists)
    {
        // If there is no metadata either in the model or in the database, then
        // we assume that the database matches the model because the common cases for
        // these scenarios are database/model first and/or an existing database.
        if (!context.Database.CompatibleWithModel(throwIfNoMetadata: false, existenceState: existence))
        {
            throw Error.DatabaseInitializationStrategy_ModelMismatch(context.GetType().Name);
        }
    }
    else
    {
        // Either the database doesn't exist, or exists and is considered empty
        context.Database.Create(existence);
        Seed(context);
        context.SaveChanges();
    }
}

标签:ef-migrations,desktop-application,c,entity-framework
来源: https://codeday.me/bug/20191118/2032128.html