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

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

问题描述

我想写一个易于理解的的DbContext 类,它需要一个定制的连接字符串,可以运行迁移,而且我可以让我使用软件包管理器来生成迁移。



我似乎在圈子中绕来绕去。



我得工作使用代码就能够了可怕的感觉对我来说。我在回答在连接字符串和迁移这个问题记录在本​​



拉狄克的回答好像比我好多了,但是我发现,当我实现它,然后尝试创建软件包管理器迁移我得到的消息




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




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



我不希望提供的实施 IDbContextFactory (和拉狄克的答案似乎以指示不需要它)



更新



我可以生成迁移,如果我包括一个构造不带参数。例如:



 公共语境():基地(的connectionStringName){} 

有关我的上下文创建我通过在app.config中的连接字符串的名称

 公共上下文(字符串CONNSTRING):基地(CONNSTRING)
{
Database.SetInitializer(新CustomInitializer());
Database.Initialize(真);
}



我终于能够同时产生迁移,并运行迁移的数据库的。用户选择



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



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

 公共类CustomInitializer:IDatabaseInitializer<语境> 
{
公共无效InitializeDatabase(上下文的背景下)
{

{
如果(!context.Database.Exists())
{
context.Database.Create();
}
,否则
{
如果
{
无功配置=新配置()(context.Database.CompatibleWithModel(假)!);
变种迁移=新DbMigrator(配置);
migrator.Configuration.TargetDatabase =
新DbConnectionInfo(context.Database.Connection.ConnectionString);
IEnumerable的<串GT;迁移= migrator.GetPendingMigrations();
的foreach(在迁移串迁移)
{
变种scriptor =新MigratorScriptingDecorator(迁移);
串脚本= scriptor.ScriptUpdate(NULL,迁移);
context.Database.ExecuteSqlCommand(脚本);
}
}
}
}
赶上(异常前)
{
}
}
}

当我把一个新的被创建的数据库,但它没有表。这将是因为我的表创建代码都在我第一次迁移。



所以中的代码!context.Database.CompatibleWithModel(假) 条件不运行。



然而可惜的是,代码也不会乱跑,第二次时,它应该有metadatamodel。



现在尝试并获得迁移正在运行...



悲伤:不是,是拉狄克的定制初始化至今



从NSGaga的意见,我已经使出退出应用程序如果我改变连接。

  VAR主=新myMDIForm(); 
master.ConnectionType = connectionType; //正在app.config中
不同的连接名称的枚举,而(master.ConnectionType = ConnectionType.None!)
{
Application.Run(主);
}


解决方案

(注:我不知道您的自定义初始化的想法,我只是看到了 - 这是对连接缓存的通用解决方案问题和迁移初始化 - 但应与变化工作)



这对我来说是什么在起作用 - 基于我所描述的此处

 静态字符串_connection; 
公共MyContext()
:基地(_connection ??DefaultConection)
{
Database.SetInitializer(新MigrateDatabaseToLatestVersion< MyContext,MyNamespace.Migrations.Configuration>());
}
公共MyContext(字符串连接)
:基地(连接)
{
_connection =连接;
Database.SetInitializer(新MigrateDatabaseToLatestVersion&下; MyContext,MyNamespace.Migrations.Configuration>());
}



几点:



1)定义静态连接在上下文 - 和你设置一个'新的'改变它持有最新值。这有助于保持同步的东西 - 不管是谁访问的DbContext拥有的同一个(这是在概念上工厂只是在眼睛容易类似,



2)迁移问题是 - 即 MigrateDatabaseToLatestVersion 缓存的连接(和整个配置内部)的内部一个只读字段 - 即使你改变它在你的的DbContext ,或任何你设置外,它就会出sync`




有没有办法解决这个越来越反而使新初始化。




3)这@Radek发现实际上该问题的解决方案 - 并与线(2)。我只是删除了初始化(真),因为它是不必要的 - 被调用时,适当的时候结果



这就是它。



有了这个,我现在能翻转我的全天候连接 - 当我想结果
(意思是我可以改变运行连接 - 迁移/创建两个或更多的数据库和不断变化的连接,同时对他们的工作)



这是我的代码实际上是连接之间...

 使用周期(VAR !翻转=真;真;翻盖采用=翻转)
{
(VAR DB =新MyContext(翻转NAME = DefaultConnection:NAME = OtherConnection?))
{
//平常DB代码
}
}




关键是设置初始化每次设置连接结果
老一时间仍然存在 - 而旧连接(你可以'T删除数据库,而应用程序正在运行)



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.

I seem to be going around in circles.

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'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

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

Where DataLayer.Context is my context class.

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

UPDATE:

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

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

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: 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.

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: No with Radek's custom initializer so far.

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

Few points:

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

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天全站免登陆