代码第一个自定义的连接字符串,并且不使用IDbContextFactory迁移 [英] Code first custom connection string and migrations without using 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 thelatest value
. That helps keeping things in synchronization - no matter who accesses the DbContext has the same one (it's similar in concept toFactory
just easier on the eyes,2) Problem with
Migrations
is - thatMigrateDatabaseToLatestVersion
caches the connection (and entire configuration internally) in areadonly
field internally - and even if you change it in yourDbContext
, 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 atruntime
- 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屋!