在使用 Unity 配置依赖项注入时,如何防止 EF Code First 尝试 运行 迁移我的数据库?
How do I prevent EF CodeFirst from trying to run migrations on my database, when configuring dependency injection with Unity?
如何防止 CodeFirst 尝试 运行 迁移我的数据库?
我正在 SqlException
抛出以下错误消息:
Invalid object name 'dbo.__MigrationHistory'.
我的日志框架正在捕获并记录这些异常。我需要防止异常发生,因此我的应用程序不会生成大量虚假日志消息。
我了解 __MigrationHistory
table 是代码优先迁移的一部分。我确实使用代码优先,但我不使用它的迁移。 (该项目使用FluentMigrator instead.) According to this blog post and this answer,要禁用该错误,我需要执行以下操作:
static InstitutionContext()
{
System.Data.Entity.Database.SetInitializer<InstitutionContext>(null);
}
(这当然是针对名为 InstitutionContext
的 DbContext
对象。)
我已经这样做了,并验证了代码行是否被命中。但是,我仍然在日志中收到错误。
This answer解释了是怎么回事,我认为基本上是正确的。简而言之,EF 正在探测 __MigrationsHistory
table,在找不到它时抛出异常,然后继续而不对迁移做任何事情。但是答案并没有解释如何抑制异常的发生。
如何防止 EF Code First 迁移尝试 运行 并抛出其 SqlException
?
更新 1
我尝试通过 App.config/Web.config 文件配置设置,但也没有用。我还尝试将它从我的 DbContext
上的静态方法移动到它自己的配置 class,如下所示:
public class MyDbConfiguration : DbConfiguration
{
public MyDbConfiguration()
{
SetDatabaseInitializer<InstitutionContext>(null);
}
}
class 与 DbContext
在同一个程序集中,就像它应该的那样。这也没有用。
更新 2
问题原来与 Unity 容器有关,以及 EF 和 Unity 是如何交互的(鉴于我的配置方式)。请参阅下面的 。
正如对我的问题注释的评论,我所做的应该有效。问题出在我的项目如何使用 Unity 依赖注入容器。
对于所有正在注册的类型,我还配置了一个虚拟方法拦截器。我是这样注册和配置我的 DbContext
的:
Container.RegisterType<IInstitutionContext, InstitutionContext>();
Container.Configure<Interception>()
.SetInterceptorFor(typeof(InstitutionContext),
new VirtualMethodInterceptor());
问题出在 VirtualMethodInterceptor
。拦截器导致 InstitutionContext
class 被包装。
Entity Framework 6 维护一个注册表,将 DbContext
类型与其配置的 DbInitializer
相关联。当它第一次看到新类型的 DbContext
时,它会在其内部注册表中查找应该调用哪个 DbInitializer
。它试图根据 DbContext
的类型找到 DbInitializer
。如果它没有找到已注册的 DbInitializer
,它会使用默认的初始化程序,即 CreateDatabaseIfNotExists
.
但是当 VirtualMethodInterceptor
被配置为给定的 DbContext
类型(在我的例子中,InstitutionContext
),Unity 容器不会直接实例化 InstitutionContext
.相反,它包装 InstitutionContext
以便能够拦截虚拟方法。当 EF6 尝试定位类型以查找其 DbInitializer
时,它会检查 DbContext 的类型,这是一个包装类型,NOT InstitutionContext
类型。所以它永远找不到匹配的类型,并回退到使用默认的数据库初始化程序。
删除 DbContext
类型的拦截器解决了这个问题。
tl;dr: 确保您的 DbContext
没有被其他类型包裹。要使 EF6 的 DbInitializer
配置正常工作,它必须检查正确的 DbContext
类型。如果 DbContext
是从已注册 DbInitializer
的类型继承的,它将不起作用,如果 DbContext
是包装类型,它将不起作用。
如何防止 CodeFirst 尝试 运行 迁移我的数据库?
我正在 SqlException
抛出以下错误消息:
Invalid object name 'dbo.__MigrationHistory'.
我的日志框架正在捕获并记录这些异常。我需要防止异常发生,因此我的应用程序不会生成大量虚假日志消息。
我了解 __MigrationHistory
table 是代码优先迁移的一部分。我确实使用代码优先,但我不使用它的迁移。 (该项目使用FluentMigrator instead.) According to this blog post and this answer,要禁用该错误,我需要执行以下操作:
static InstitutionContext()
{
System.Data.Entity.Database.SetInitializer<InstitutionContext>(null);
}
(这当然是针对名为 InstitutionContext
的 DbContext
对象。)
我已经这样做了,并验证了代码行是否被命中。但是,我仍然在日志中收到错误。
This answer解释了是怎么回事,我认为基本上是正确的。简而言之,EF 正在探测 __MigrationsHistory
table,在找不到它时抛出异常,然后继续而不对迁移做任何事情。但是答案并没有解释如何抑制异常的发生。
如何防止 EF Code First 迁移尝试 运行 并抛出其 SqlException
?
更新 1
我尝试通过 App.config/Web.config 文件配置设置,但也没有用。我还尝试将它从我的 DbContext
上的静态方法移动到它自己的配置 class,如下所示:
public class MyDbConfiguration : DbConfiguration
{
public MyDbConfiguration()
{
SetDatabaseInitializer<InstitutionContext>(null);
}
}
class 与 DbContext
在同一个程序集中,就像它应该的那样。这也没有用。
更新 2
问题原来与 Unity 容器有关,以及 EF 和 Unity 是如何交互的(鉴于我的配置方式)。请参阅下面的
正如对我的问题注释的评论,我所做的应该有效。问题出在我的项目如何使用 Unity 依赖注入容器。
对于所有正在注册的类型,我还配置了一个虚拟方法拦截器。我是这样注册和配置我的 DbContext
的:
Container.RegisterType<IInstitutionContext, InstitutionContext>();
Container.Configure<Interception>()
.SetInterceptorFor(typeof(InstitutionContext),
new VirtualMethodInterceptor());
问题出在 VirtualMethodInterceptor
。拦截器导致 InstitutionContext
class 被包装。
Entity Framework 6 维护一个注册表,将 DbContext
类型与其配置的 DbInitializer
相关联。当它第一次看到新类型的 DbContext
时,它会在其内部注册表中查找应该调用哪个 DbInitializer
。它试图根据 DbContext
的类型找到 DbInitializer
。如果它没有找到已注册的 DbInitializer
,它会使用默认的初始化程序,即 CreateDatabaseIfNotExists
.
但是当 VirtualMethodInterceptor
被配置为给定的 DbContext
类型(在我的例子中,InstitutionContext
),Unity 容器不会直接实例化 InstitutionContext
.相反,它包装 InstitutionContext
以便能够拦截虚拟方法。当 EF6 尝试定位类型以查找其 DbInitializer
时,它会检查 DbContext 的类型,这是一个包装类型,NOT InstitutionContext
类型。所以它永远找不到匹配的类型,并回退到使用默认的数据库初始化程序。
删除 DbContext
类型的拦截器解决了这个问题。
tl;dr: 确保您的 DbContext
没有被其他类型包裹。要使 EF6 的 DbInitializer
配置正常工作,它必须检查正确的 DbContext
类型。如果 DbContext
是从已注册 DbInitializer
的类型继承的,它将不起作用,如果 DbContext
是包装类型,它将不起作用。