代码第一个自定义连接字符串和迁移,而不使用IDbContextFactory [英] Code first custom connection string and migrations without using IDbContextFactory

查看:194
本文介绍了代码第一个自定义连接字符串和迁移,而不使用IDbContextFactory的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to write an easy to understand DBContext class that takes a custom connection string, can run migrations, and that I allows me to generate migrations using Package Manager.

我似乎在圈中出现。

我已经能够使用代码对我感到可怕我在回答关于连接字符串和迁移的问题时记录了这一点。 / a>

I have been able to get it working using code that feels awful to me. I documented this in my answer to This question on connection string and migrations.

Radek的答案看起来比我的好多了,但是我发现,当我实现它,然后尝试在Package Manager中创建迁移时,我收到消息



Radek's answer looks much better than mine, but I find that when I implement it and then try and create a migration in Package Manager I get the message


目标上下文DataLayer.Context不可构造。添加一个默认构造函数或提供一个IDbContextFactory的实现。

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

其中 DataLayer.Context 是我的上下文类。

我不想提供 IDbContextFactory 的实现(和Radek的回答似乎表示不需要)

I don't want to provide an implementation of IDbContextFactory ( and Radek's answer seems to indicate it isn't needed )

更新:

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

I can generate a migration if I include a constructor with no parameter. For example

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

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

For my context creation I pass the name of the connection string in app.config

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

最后我可以同时生成迁移,并为数据库运行迁移用户选择。

At last I am able to both generate migrations, and run migrations for databases that the user selects.

HOWEVER:
当我删除数据库然后运行我的应用程序我有问题。

HOWEVER: When I drop the database and then run my app I have problems.

我使用的初始化代码,从上面的链接是

The initialiser code I am using, from the link above is

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

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

When I drop the database a new one gets created but it has no tables. That would be because my table creation code is all in my first migration.

所以在$ code>!context.Database.CompatibleWithModel(false) 条件不运行。

So the code inside the !context.Database.CompatibleWithModel(false) condition does not run.

但是,代码也不会在第二次运行时应该有元数据。

However alas, the code also does not run the second time around when it should have the metadatamodel.

现在尝试运行迁移...

Now to try and get the migration running...

SADNESS:到目前为止,Radek的自定义初始值设定。

SADNESS: No with Radek's custom initializer so far.

从NSGaga的意见我已经诉诸于退出应用程序,如果我更改连接。

From NSGaga's comments I have resorted to exiting the application if I change connection.

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


推荐答案

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



这对我有用 - 根据我描述的错误行为
此处

(note: I have no idea about your custom initializer, I just saw that - this is a general solution to the connection caching problem and migration initializer - but should work with variations)


This is what works for me - and based on the buggy behavior that I described 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)在您的上下文中定义 static 连接 - 当您设置新的更改它以保存最新值。这有助于保持事物同步 - 无论访问DbContext是否具有相同的(在概念上与 Factory 类似,只是更容易在眼睛,

1) Define static connection in your context - and as you set a 'new one' change it to hold the latest value. That helps keeping things in synchronization - no matter who accesses the DbContext has the same one (it's similar in concept to Factory just easier on the eyes,

2) Migrations 的问题是 - MigrateDatabaseToLatestVersion 缓存连接内部的整个配置),而在内部的 readonly 字段中,即使您在 DbContext 中更改它,或者任何您设置在外面,它变得不同步

2) Problem with Migrations is - that MigrateDatabaseToLatestVersion caches the connection (and entire configuration internally) in a readonly field internally - and even if you change it in your DbContext, or whatever you set outside, it gets 'out of sync`.


没有办法解决这个问题,而是建立一个新的初始化程序。

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

3)@Radek发现的是实际上是该问题的解决方案 - 并符合(2)。我刚刚删除了 Initialize(true),因为它是不必要的 - 当时间是正确的时被调用。


$ b $这就是它。

3) What @Radek discovered was actually the solution for that problem - and in line with (2). I just removed the Initialize(true) as it's unnecessary - that gets called when 'the time is right'.


That's about it.

有了这个,我现在可以在全天候连接我的连接 - 我想要的。

(意味着我可以在运行时更改连接 - 迁移/创建两个或更多数据库,并不断更改连接并同时处理它们)

With this I can now flip my connections around the clock - and as I want.
(meaning I can change connection at runtime - migrate/create two, or more, databases and keep changing connections and working on them simultaneously)

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

And this is the code I actually use to cycle between connections...

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




关键是每次设置连接时设置初始值设置。

旧的仍然在 - 和旧的连接(你可以在应用程序运行时不要删除Db)

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)

这篇关于代码第一个自定义连接字符串和迁移,而不使用IDbContextFactory的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆