gpt4 book ai didi

c# - 在不使用 IDbContextFactory 的情况下首先编写自定义连接字符串和迁移

转载 作者:太空狗 更新时间:2023-10-29 18:35:46 25 4
gpt4 key购买 nike

我正在尝试编写一个易于理解的 DBContext 类,它采用自定义连接字符串,可以运行迁移,并且允许我使用包管理器生成迁移。

我好像在兜圈子。

我已经能够使用我觉得很糟糕的代码让它工作。我在对 This question on connection string and migrations. 的回答中记录了这一点

Radek 的答案看起来比我的好得多,但我发现当我实现它然后尝试在包管理器中创建迁移时,我得到了消息

The target context 'DataLayer.Context' is not constructible. Add a default constructor or provide an implementation of IDbContextFactory.

DataLayer.Context 是我的上下文类。

我不想提供 IDbContextFactory 的实现(而且 Radek 的回答似乎表明不需要它)

更新:

如果我包含一个没有参数的构造函数,我可以生成一个迁移。例如

public Context() : base("ConnectionStringName") { }

为了创建上下文,我在 app.config 中传递了连接字符串的名称

public Context(string connString) : base(connString)
{
Database.SetInitializer(new CustomInitializer());
Database.Initialize(true);
}

最后,我能够为用户选择的数据库生成迁移和运行迁移。

但是:当我删除数据库然后运行我的应用程序时,我遇到了问题。

我正在使用的初始化代码,来自上面的链接是

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

当我删除数据库时,会创建一个新数据库,但它没有表。那是因为我的表创建代码都在我的第一次迁移中。

因此 !context.Database.CompatibleWithModel(false) 条件中的代码不会运行。

然而,遗憾的是,代码也没有在它应该具有元数据模型时第二次运行。

现在尝试运行迁移...

悲伤:到目前为止,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);
}

最佳答案

(注意:我不知道您的自定义初始化程序,我只是看到 - 这是连接缓存问题和迁移初始化程序的通用解决方案 - 但应该适用于变体)


这对我有用 - 并且基于我描述的错误行为 here .

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

几点:

1) 在您的上下文中定义静态 连接 - 当您设置一个“新连接”时,将其更改为保存最新值。这有助于保持同步 - 无论谁访问 DbContext 都有相同的(它在概念上类似于 Factory 只是看起来更容易,

2) Migrations 的问题是 - MigrateDatabaseToLatestVersion 将连接(以及内部的整个配置)缓存在内部的 readonly 字段中- 即使您在 DbContext 或您在外部设置的任何内容中更改它,它也会“不同步”

There is no way getting around that but to make a 'new initializer'.

3) @Radek 发现的实际上是该问题的解决方案 - 并且符合 (2)。我刚刚删除了 Initialize(true),因为它是不必要的 - 它会在“时机成熟”时被调用。


就是这样。

有了这个,我现在可以翻转我的连接全天候 - 随心所欲。
(这意味着我可以在 runtime 更改连接 - 迁移/创建两个或更多数据库并继续更改连接并同时处理它们)

这是我实际用来在连接之间循环的代码......

for (var flip = true; true; flip = !flip)
{
using (var db = new MyContext(flip ? "Name=DefaultConnection" : "Name=OtherConnection"))
{
// usual db code
}
}

The key is to set initializer each time you set the connection.
The old one is still around - and the old connection (you can't delete the Db while app is running)

关于c# - 在不使用 IDbContextFactory 的情况下首先编写自定义连接字符串和迁移,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15926897/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com