Kir*_*eed 8 c# migration ef-code-first
我正在尝试编写一个易于理解的DBContext类,它采用自定义连接字符串,可以运行迁移,并且我允许使用包管理器生成迁移.
我好像在四处走动.
我已经能够使用对我来说非常糟糕的代码来使用它.我在关于连接字符串和迁移的这个问题的答案中记录了这一点.
Radek的答案看起来比我的好,但是我发现当我实现它然后尝试在Package Manager中创建一个迁移时,我得到了消息
目标上下文'DataLayer.Context'不可构造.添加默认构造函数或提供IDbContextFactory的实现.
DataLayer.Context我的上下文类在哪里.
我不想提供一个实现IDbContextFactory(并且Radek的答案似乎表明它不需要)
更新:
如果我包含一个没有参数的构造函数,我可以生成一个迁移.例如
public Context() : base("ConnectionStringName") { }
Run Code Online (Sandbox Code Playgroud)
对于我的上下文创建,我在app.config中传递连接字符串的名称
public Context(string connString) : base(connString)
{
Database.SetInitializer(new CustomInitializer());
Database.Initialize(true);
}
Run Code Online (Sandbox Code Playgroud)
最后,我既可以生成迁移,也可以为用户选择的数据库运行迁移.
但是:当我删除数据库然后运行我的应用程序时,我遇到了问题.
我正在使用的初始化代码,来自上面的链接
public class CustomInitializer : IDatabaseInitializer<Context>
{
public void InitializeDatabase(Context context)
{
try
{
if (!context.Database.Exists())
{
context.Database.Create();
}
else
{
if (!context.Database.CompatibleWithModel(false))
{
var configuration = new Configuration();
var migrator = new DbMigrator(configuration);
migrator.Configuration.TargetDatabase =
new DbConnectionInfo(context.Database.Connection.ConnectionString);
IEnumerable<string> migrations = migrator.GetPendingMigrations();
foreach (string migration in migrations)
{
var scriptor = new MigratorScriptingDecorator(migrator);
string script = scriptor.ScriptUpdate(null, migration);
context.Database.ExecuteSqlCommand(script);
}
}
}
}
catch (Exception ex)
{
}
}
}
Run Code Online (Sandbox Code Playgroud)
当我删除数据库时,会创建一个新数据库但它没有表.那是因为我的表创建代码都在我的第一次迁移中.
所以!context.Database.CompatibleWithModel(false)条件中的代码不会运行.
然而,唉,代码也不会第二次运行它应该有metadatamodel.
现在尝试让迁移运行......
SADNESS:到目前为止,没有Radek的自定义初始化程序.
根据NSGaga的评论,如果我改变连接,我已经退出了应用程序.
var master = new myMDIForm();
master.ConnectionType = connectionType; // being an enum of the different connection names in app.config
while (master.ConnectionType != ConnectionType.None )
{
Application.Run(master);
}
Run Code Online (Sandbox Code Playgroud)
(注意:我不知道你的自定义初始化程序,我只是看到了 - 这是connection caching问题和迁移初始化程序的一般解决方案- 但应该使用变体)
static string _connection;
public MyContext()
: base(_connection ?? "DefaultConection")
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, MyNamespace.Migrations.Configuration>());
}
public MyContext(string connection)
: base(connection)
{
_connection = connection;
Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, MyNamespace.Migrations.Configuration>());
}
Run Code Online (Sandbox Code Playgroud)
几点:
1)static在你的上下文中定义连接 - 当你设置'新的'时,改变它以保持连接latest value.这有助于保持事物同步 - 无论谁访问DbContext都有相同的(它在概念上类似于Factory眼睛更容易,
2)问题Migrations在于 - MigrateDatabaseToLatestVersion在内部缓存连接(以及内部的整个配置)readonly- 即使你在自己DbContext或外面设置的任何内容中更改它,它也会"不同步".
没有办法解决这个问题,而是制作一个"新的初始化程序".
3)@ Radek发现的实际上是该问题的解决方案 - 并符合(2).我只是删除了Initialize(true)它,因为它是不必要的 - 当'时间合适'时会被调用.
有了这个,我现在可以flip全天候连接 - 就像我想要的那样.
(这意味着我可以更改连接runtime- 迁移/创建两个或更多数据库并继续更改连接并同时处理它们)
这是我实际用来在连接之间循环的代码......
for (var flip = true; true; flip = !flip)
{
using (var db = new MyContext(flip ? "Name=DefaultConnection" : "Name=OtherConnection"))
{
// usual db code
}
}
Run Code Online (Sandbox Code Playgroud)
关键是要
set initializer each time you set the connection.
旧的仍然存在 - 和旧连接(在应用程序运行时无法删除Db)
| 归档时间: |
|
| 查看次数: |
6325 次 |
| 最近记录: |