【问题标题】:Code First Migrations for dynamically assembled model动态组装模型的代码优先迁移
【发布时间】:2012-11-19 02:02:59
【问题描述】:

我的数据库模型(有时称为“context”)在启动时根据安装的服务和/或插件动态组装。插件和服务通过我的 IoC 容器导出它们的模型定义片段,应用程序核心在调用 DbContext.OnModelCreating 方法时将它们拾取并运行它们。

问题是:我可以(以及如何)在此设置中使用 Code First 迁移
(以下是有关我尝试过的方法以及具体问题的更多信息)

在我之前的项目中,数据库是从一些旧代码继承而来的,所以无论如何我们都不能使用任何 Code First 数据库生成的东西。我们只是保留了一长串 delta 脚本并在部署时手动执行它们(这是一种单主机项目)。

现在我开始一个新项目,这一次,数据库是全新的,可以使用 Code First。最初,我对 Code First 迁移感到非常兴奋,这似乎是要走的路。直到我真正尝试过。很明显,最初的尝试失败了,因为我的项目中没有明确定义的DbContext

到目前为止,似乎唯一可行的选择是手动编码迁移,我对此非常满意。然而,事实证明,这并不是仅仅创建几个继承自DbMigration 的类那么简单。

在对一个小型测试项目进行了一些实验后,我发现迁移自动生成器添加了 IMigrationMetadata 的实现,其中包含我的模型的哈希值作为 Source 的值和Target 属性。据推测,此哈希随后用于识别从数据库的“当前”状态(如__MigrationHistory 表中记录的)迁移到代码中模型定义的最新状态的路径。这完全有道理,但是...

当然,我不知道从哪里获取模型的哈希值,这使我无法在迁移中实现 IMigrationMetadata

另一方面,我看到元数据接口不包含在DbMigration 类本身中,这让我认为它可能是可选的。然后,迁移实际上可以在没有哈希值的情况下工作,但问题是 - 如何?

我在互联网上能找到的所有信息都只是简单、非常基础的教程。没有关于如何手动创建迁移的信息(以及它是否受支持)。没有关于它如何实际工作以及如何扩展它的文档。而且从外面看不太明显。
此时我已准备好求助于 ILSpy,但整个 EF 非常复杂,我担心我可能无法在合理的时间内找到我需要的东西。

【问题讨论】:

    标签: entity-framework ef-code-first entity-framework-migrations


    【解决方案1】:

    您可以将以下一些想法汇集在一起​​,以找到适合您的解决方案。我意识到我在我们的其他帖子中提到了其中一些,但我将它们包括在这里以供其他阅读此问题的人使用。

    • Automatic migrations 允许 Code First 自动计算并将更改应用到数据库。
    • 您可以编写自己的代码来生成和应用迁移。我写了一篇关于应用迁移的postMigrationsScaffolder 类将帮助您创建迁移。

    【讨论】:

    • 但是它是如何工作的呢?为什么我必须使用MigrationsScaffolder?它有什么我不能用手做的?
    【解决方案2】:

    当您运行项目时,会在数据库中创建一个额外的表。

                  EdmMetadata table
    

    哈希总是在 EdmMetadata 实体和当前代码优先模型的帮助下创建的。它是存储在数据库的 EdmMetadata 表中的 SHA-256 哈希。你可以从那张桌子上得到它。

    要遵循的方法是:

    1. 使用获取当前模型的哈希

                var hash=GetModelHash(OldContext);
      
    2. 使用检查代码中的模型(新模型)是否与数据库中的模型(旧模型)兼容

                 CompatibleWithModel(hash,CurrentContext,ObjectContext)
      

    此方法返回 bool

    1. 如果不兼容,则删除数据库中已有的表。

    2. 创建新表

    3. 将当前哈希保存到数据库

    4. 播种数据。

    代码可能如下所示:

                    {
                            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);
                    }
    

    一定要让类继承自

        IDatabaseInitializer<T> where T:DbContext
    

    【讨论】:

    • 我将其作为代码发布,因为我的答案提交存在一些问题。
    • 首先,您的信息有点过时了。其次,即使不是,我认为我的客户不会因为每次升级时从数据库中删除所有数据而感到开心。
    • 第三,看起来您只是从这里复制和粘贴:stackoverflow.com/questions/4031431/…,不是吗?
    • 实际上,stackoverflow.com/questions/4031431/… 处的代码是从 Microsoft 的 Entity Framework 网站复制而来的。我从那里研究过它,所以我的代码类似于 Microsoft 的代码...但是您的链接提供了整个副本和从微软粘贴
    猜你喜欢
    • 2016-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多