c# - 在使用 Unity 配置依赖注入(inject)时,如何防止 EF Code First 尝试在我的数据库上运行迁移?

标签 c# entity-framework ef-code-first unity-container entity-framework-migrations

如何防止 CodeFirst 尝试在我的数据库上运行迁移?

我收到 SqlException 并抛出以下错误消息:

Invalid object name 'dbo.__MigrationHistory'.

我的日志框架正在捕获并记录这些异常。我需要防止异常发生,以便我的应用程序不会生成大量虚假日志消息。

我了解 __MigrationHistory 表是代码优先迁移的一部分。我确实使用代码优先,但我使用它的迁移。 (该项目使用 FluentMigrator 代替。)根据 this blog postthis answer , 要禁用错误,我需要执行以下操作:

static InstitutionContext()
{
    System.Data.Entity.Database.SetInitializer<InstitutionContext>(null);
}

(当然,这是针对名为 InstitutionContextDbContext 对象。)

我已经这样做了,并验证了代码行是否被命中。但是,我仍然在日志中收到错误。

This answer解释了正在发生的事情,我认为这基本上是正确的。简而言之,EF 正在探测 __MigrationsHistory 表,在找不到它时引发异常,然后继续而不对迁移执行任何操作。但是答案并没有解释如何抑制异常的发生。

如何防止 EF Code First 迁移尝试运行并抛出其 SqlException

更新 1

我尝试通过 App.config/Web.config 文件配置设置,但也没有用。我还尝试将它从我的 DbContext 上的静态方法移动到它自己的配置类,如下所示:

public class MyDbConfiguration : DbConfiguration
{
    public MyDbConfiguration()
    {
        SetDatabaseInitializer<InstitutionContext>(null);
    }
}

该类与 DbContext 应在同一个程序集中。这也不起作用。

更新 2

问题原来与 Unity 容器有关,以及 EF 和 Unity 是如何交互的(鉴于我的配置方式)。参见 my answer下面。

最佳答案

作为对我的问题注释的评论,我所做的应该有效。问题出在我的项目如何使用 Unity 依赖项注入(inject)容器。

对于正在注册的所有类型,我还配置了一个虚拟方法拦截器。我正在像这样注册和配置我的 DbContext:

Container.RegisterType<IInstitutionContext, InstitutionContext>();
Container.Configure<Interception>()
    .SetInterceptorFor(typeof(InstitutionContext), 
        new VirtualMethodInterceptor());

问题是 VirtualMethodInterceptor。拦截器导致 InstitutionContext 类被包装。

Entity Framework 6 维护一个注册表,将 DbContext 类型与其配置的 DbInitializer 相关联。当它第一次看到新类型的 DbContext 时,它会在其内部注册表中查找应该调用哪个 DbInitializer。它尝试根据 DbContext 的类型找到 DbInitializer。如果它没有找到已注册的 DbInitializer,它会使用默认的初始化程序,即 CreateDatabaseIfNotExists

但是当 VirtualMethodInterceptor 被配置为给定的 DbContext 类型(在我的例子中,InstitutionContext),Unity 容器将不会实例化InstitutionContext 直接。相反,它包装 InstitutionContext 以便能够拦截虚拟方法。当 EF6 尝试定位类型以查找其 DbInitializer 时,它会检查 DbContext 的类型,这是一个包装类型,不是 InstitutionContext 键入。因此它永远找不到匹配的类型,并回退到使用默认的数据库初始化器。

删除 DbContext 类型的拦截器解决了这个问题。

tl;dr: 确保您的 DbContext 未被其他类型包装。要使 EF6 的 DbInitializer 配置正常工作,它必须检查正确的 DbContext 类型。如果 DbContext 是从具有已注册的 DbInitializer 的类型继承的,它将不起作用,如果 DbContext 是包装器类型。

关于c# - 在使用 Unity 配置依赖注入(inject)时,如何防止 EF Code First 尝试在我的数据库上运行迁移?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39400102/

相关文章:

c# - Entity Framework 6 键和列属性去哪儿了

c# - 通过 DataAnnotation 强制外键列名称不起作用

c# - Ninject 注入(inject)接口(interface)的多重绑定(bind)

c# - 异步 Web 请求超时 => 使 IIS 崩溃

c# - 如何在 EF 迁移中使用 SqlResource 方法?

asp.net-mvc - Entity Framework 无效的列名Id(来自同一主表的两个外键)

c# - Entity Framework 自动重命名多对多表而无需任何更改

c# - 我如何消除具有某些祖先的元素?

c# - .NET 装箱/拆箱与类型转换性能

c# - 将父级和子级关系集合映射到 EF6 中的单个表