C# 在EF中IDatabaseInitializer的正确用法是什么?
我有一个自定义数据库初始化器,如下所示C# 在EF中IDatabaseInitializer的正确用法是什么?,c#,entity-framework,ef-code-first,entity-framework-migrations,entity-framework-6,C#,Entity Framework,Ef Code First,Entity Framework Migrations,Entity Framework 6,我有一个自定义数据库初始化器,如下所示 /// <summary> /// Implements the IDatabaseInitializer to provide a custom database initialisation for the context. /// </summary> /// <typeparam name="TContext">TContext is the DbContext</typeparam> public
/// <summary>
/// Implements the IDatabaseInitializer to provide a custom database initialisation for the context.
/// </summary>
/// <typeparam name="TContext">TContext is the DbContext</typeparam>
public class ParikshaDataBaseInitializer<TContext> : IDatabaseInitializer<TContext> where TContext : DbContext
{
/// <summary>
/// The method to Initialise the database.
/// Takes care of the database cannot be dropped since it is in use problem while dropping and recreating the database.
/// </summary>
/// <param name="context">The DbContext on which to run the initialiser</param>
public void InitializeDatabase(TContext context)
{
var exists = context.Database.Exists();
try
{
if (exists && context.Database.CompatibleWithModel(true))
{
// everything is good , we are done
return;
}
if (!exists)
{
context.Database.Create();
}
}
catch (Exception)
{
//Something is wrong , either we could not locate the metadata or the model is not compatible.
if (exists)
{
context.Database.ExecuteSqlCommand("ALTER DATABASE Pariksha SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
context.Database.ExecuteSqlCommand("USE Master DROP DATABASE Pariksha");
context.SaveChanges();
}
context.Database.Create();
}
}
}
一些论坛在构造函数中也提出了这一点,这似乎有点奇怪,因为我不想每次使用上下文时都检查db和模式是否正确。那么,这项技术的可能用途是什么?或者我是否认为这项建议的上下文是错误的
public ParikshaContext() : base("Pariksha")
{
Database.SetInitializer(new ParikshaDataBaseInitializer<ParikshaContext>());
}
public ParikshaContext():base(“Pariksha”)
{
SetInitializer(新的ParikshaDataBaseInitializer());
}
总之,
这是我尝试的
Db初始值设定项
,它将迁移
初始值设定项和默认的Db Create
初始值设定项与种子设定相结合。(注意:这并不理想,更像是一个简单的练习,但它为您在这里提出的问题提供了一个解决方案,大部分是有效的-只需检查我所做的所有更新)
至于为什么
和如何
——为了充分理解这一点,我建议您也参考(这是新版本,但在许多方面类似)
1)
a)Db初始值设定项通常只被调用一次(每个连接),并且当您第一次尝试访问“模型”时(第一次查询或类似查询)。在初始值设定项中放置断点以进行检查
所以,将它放在构造函数中是完全安全的(尽管我更喜欢在启动时使用它,配置也一样)只有在需要初始化时才会调用它(并且使用了最后一组),您不应该手动调用它
无论如何,要强制初始化,您可以执行this.Database.Initialize(force:true)代码>
有关切换连接的详细信息,请参阅我关于问题的帖子
b)如果您创建了自己的IDatabaseInitializer
并且仍然希望迁移并行运行
您不应该只从外部调用DbMigrator
,因为您的自定义初始值设定项将错过整个“db创建”(例如,如果您希望种子或其他内容,请查看上面的示例)
这两个东西都是有效的“初始值设定者”——因此您需要将它们集成到一个,这将以某种方式链接东西。请记住,执行顺序
非常重要(有关问题,请参见上面的示例)-您应该检查“空条件”,然后调用DbMigrator
,然后进行自己的初始化。我使用一个初始值设定项作为基类,并合并了另一个
如果您只想种子,您可以使用迁移配置,这是最简单的(如果可能的话)
2)
是相当“开放式”的,没有单一的答案。通常它是有效的,但问题会扩大
- 迁移是三件事(在我看来)-您的代码模型/实体、数据库/表和数据库中的
\uu MigrationHistory
系统表。所有三个都需要保持同步。如果出现“不同步”,则可以删除迁移表,重新创建迁移(带有保留现有数据库的标志),然后像以前一样继续—即,有一些解决方案可用于实时数据。为此,请看
- 移动数据库时,您需要有删除/创建数据库的权限
- 确保您的连接正确(配置中的更改-并与DbContext名称或ctor同步)
- 保持简单,不要做花哨的事情或从代码切换连接(可能有问题),等等
- 不要混用数据库/代码
版本-即一个代码实体版本-一个数据库。如果您希望使用不同的代码版本(例如,登台、生产)共享同一个Db,则不要(多租户解决方案将在EF6中提供,例如)
如果需要手动应用数据库-通过更新数据库生成脚本
-并应用该脚本,请不要手动操作,否则会出错(迁移历史记录表)-请参阅
…仅举几个例子。在我看来,它是相当稳定和可用的——但是如果你遵循规则——并且知道限制是什么
类CreateAndMigrateDatabaseInitializer
:CreateDatabaseIfNotExists,IDatabaseInitializer
其中TContext:DbContext
其中TConfiguration:DbMigrationsConfiguration,new()
{
专用只读DbMigrationsConfiguration\u配置;
public CreateAndMigrateDatabaseInitializer()
{
_配置=新的TConfiguration();
}
public CreateAndMigrateDatabaseInitializer(字符串连接)
{
Contract.Requires(!string.IsNullOrEmpty(connection),“connection”);
_配置=新的t配置
{
TargetDatabase=新的DbConnectionInfo(连接)
};
}
void IDatabaseInitializer.InitializeDatabase(TContext上下文)
{
var doseed=!context.Database.Exists();
//&&new DatabaseTableChecker()。AnyModelTableExists(上下文);
//检查是否要播种-我们“缺少”了“AnyModelTableExists”
//…如果需要,可以复制/执行其他操作。。。
var migrator=新的DbMigrator(_配置);
//if(doseed | |!context.Database.CompatibleWithModel(false))
if(migrator.GetPendingMigrations().Any())
migrator.Update();
//继续使用“种子”的“CreateDatabaseIfNotExists”
base.InitializeDatabase(上下文);
if(doseed)
{
种子(上下文);
SaveChanges();
}
}
受保护的覆盖无效种子(TContext上下文)
{
}
}
总之,
1) what is the correct use-case for the different techniques available ?
2) what would be the ideal strategy so that the migrations work in all conditions
and when we move databases from one environment to another ?
退后一步,问问你自己,你什么时候想让英孚来做这件事
public ParikshaContext() : base("Pariksha")
{
Database.SetInitializer(new ParikshaDataBaseInitializer<ParikshaContext>());
}
class CreateAndMigrateDatabaseInitializer<TContext, TConfiguration>
: CreateDatabaseIfNotExists<TContext>, IDatabaseInitializer<TContext>
where TContext : DbContext
where TConfiguration : DbMigrationsConfiguration<TContext>, new()
{
private readonly DbMigrationsConfiguration _configuration;
public CreateAndMigrateDatabaseInitializer()
{
_configuration = new TConfiguration();
}
public CreateAndMigrateDatabaseInitializer(string connection)
{
Contract.Requires(!string.IsNullOrEmpty(connection), "connection");
_configuration = new TConfiguration
{
TargetDatabase = new DbConnectionInfo(connection)
};
}
void IDatabaseInitializer<TContext>.InitializeDatabase(TContext context)
{
var doseed = !context.Database.Exists();
// && new DatabaseTableChecker().AnyModelTableExists(context);
// check to see if to seed - we 'lack' the 'AnyModelTableExists'
// ...could be copied/done otherwise if needed...
var migrator = new DbMigrator(_configuration);
// if (doseed || !context.Database.CompatibleWithModel(false))
if (migrator.GetPendingMigrations().Any())
migrator.Update();
// move on with the 'CreateDatabaseIfNotExists' for the 'Seed'
base.InitializeDatabase(context);
if (doseed)
{
Seed(context);
context.SaveChanges();
}
}
protected override void Seed(TContext context)
{
}
}
1) what is the correct use-case for the different techniques available ?
2) what would be the ideal strategy so that the migrations work in all conditions
and when we move databases from one environment to another ?
Database.SetInitializer(new DomainInitializer());