如何重写EFef6 dbcontextt 获取链接字符串的方法

I'm using Entity Framework 5 with Code First Migrations. I have a DataStore class which derives from DbContext:
public class DataStore : DbContext, IDataStore
public int UserID { }
public DataStore(int userId, string connectionString) : base(connectionString)
UserID = userId;
public virtual IDbSet&User& Users { }
// Rest of code here
And a factory class which creates instances of the DataStore class:
public class DataStoreFactory : Disposable, IDataStoreFactory
private DataStore _
private int _userId;
private string _connectionS
public DataStoreFactory(int userId, string connectionString)
_userId = userId;
_connectionString = connectionS
public IDataStore Get()
_database = new DataStore(_userId, _connectionString);
protected override void DisposeCore()
if (_database != null) _database.Dispose();
These classes have their constructor parameters injected at runtime with . So far so good, everything works great!
The problem arises when we get to migrations: because my DataStore context class doesn't have a default constructor, I need to supply an implementation of IDbContextFactory&T& so that Code First Migrations can instantiate it:
public class MigrationDataStoreFactory : IDbContextFactory&DataStore&
public DataStore Create()
// Need to inject connection string so we can pass it to this constructor
return new DataStore(0, "CONNECTION_STRING_NEEDED_HERE");
The issue is that I can't figure out how I can inject the connection string into this class. I can't create a new constructor with a connection string parameter like this:
public class MigrationDataStoreFactory : IDbContextFactory&DataStore&
public string _connectionString { }
public MigrationDataStoreFactory(string connectionString)
_connectionString = connectionS
public DataStore Create()
return new DataStore(0, new DateTimeProvider(() =& DateTime.Now), _connectionString);
If I do, I get the following exception thrown by Migrations at runtime:
[InvalidOperationException: The context factory type 'MigrationDataStoreFactory' must have a public default constructor.]
System.Data.Entity.Infrastructure.DbContextInfo.CreateActivator() +326
System.Data.Entity.Infrastructure.DbContextInfo..ctor(Type contextType, DbProviderInfo modelProviderInfo, AppConfig config,
DbConnectionInfo connectionInfo) +106
System.Data.Entity.Infrastructure.DbContextInfo..ctor(Type contextType) +52
System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration, DbContext usersContext) +202
System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration) +66
System.Data.Entity.MigrateDatabaseToLatestVersion`2.InitializeDatabase(TContext context) +50
// Truncated stack trace, but you get the idea
Aside from that, this class is not instantiated by U it seems to just be called by convention by Code First Migrations somehow, so even if I could do that it wouldn't really help...
Everything works fine if I hard-code the connection string in that method, but I don't want to do that, for obvious reasons.
Can anyone help please?
解决方案 Here's the approach I eventually used, using the custom IDatabaseInitializer&T& code from , which helped me out a great deal.
First we add another constructor to the DataStore class (DbContext) which doesn't require the connection string parameter:
public class DataStore : DbContext, IDataStore
public int UserID { }
// This is the constructor that will be called by the factory class
// if it is initialised without a connection string parameter
public DataStore(int userId)
UserID = userId;
public DataStore(int userId, string connectionString) : base(connectionString)
UserID = userId;
public virtual IDbSet&User& Users { }
// Rest of code here
Then we do the same for the factory class:
public class DataStoreFactory : Disposable, IDataStoreFactory
private DataStore _
private int _userId;
private string _connectionS
// This is the constructor that will be called by the
// MigrationDataStoreFactory class
public DataStoreFactory(int userId)
_userId = userId;
public DataStoreFactory(int userId, string connectionString)
_userId = userId;
_connectionString = connectionS
public IDataStore Get()
// If we have a connection string, construct our context with it,
// if not, use the new constructor
if(_connectionString != null)
_database = new DataStore(_userId, _dateTimeServices, _connectionString);
_database = new DataStore(_userId, _dateTimeServices);
protected override void DisposeCore()
if (_database != null) _database.Dispose();
This is the custom initializer code:
public class MigrateDatabaseToLatestVersionWithConnectionString&TContext, TMigrationsConfiguration& : IDatabaseInitializer&TContext&
where TContext : DbContext
where TMigrationsConfiguration : DbMigrationsConfiguration&TContext&, new()
private readonly DbMigrationsConfiguration _
public MigrateDatabaseToLatestVersionWithConnectionString()
_config = new TMigrationsConfiguration();
public MigrateDatabaseToLatestVersionWithConnectionString(string connectionString)
// Set the TargetDatabase for migrations to use the supplied connection string
_config = new TMigrationsConfiguration {
TargetDatabase = new DbConnectionInfo(connectionString,
"System.Data.SqlClient")
public void InitializeDatabase(TContext context)
// Update the migrator with the config containing the right connection string
DbMigrator dbMigrator = new DbMigrator(_config);
dbMigrator.Update();
Our custom context factory (which is only ever called by Code First Migrations) can now carry on using the DataStore constructor which doesn't require a connection string:
public class MigrationDataStoreFactory : IDbContextFactory&DataStore&
public DataStore Create()
return new DataStore(0);
As long as we set the database initializer to our custom initializer and pass in the connection string (which in my case is done in Global.asax), migrations will use the correct connection:
Database.SetInitializer&DataStore&(new MigrateDatabaseToLatestVersionWithConnectionString&DataStore, MyMigrationsConfiguration&(INJECTED_CONNECTION_STRING_HERE));
Hope all that makes sense—feel free to ask for clarification in the comments.
本文地址: &
我使用实体框架与5 code首先迁移。我有一个从派生的数据存储类的DbContext : 公共类数据存储:的DbContext,IDataStore{
公众诠释用户名{搞定;私人集; }
公共数据存储(INT userid,字符串的connectionString):基地(的connectionString)
用户名=用户
公共虚拟IDbSet&使用者>用户{搞定;组; }
code这里//休息} 和它创建数据存储类的实例的工厂类: 公共类DataStoreFactory:一次性,IDataStoreFactory{
私人数据存储_
私人诠释_userId;
私人字符串_connectionS
公共DataStoreFactory(INT userid,字符串的connectionString)
_userId =用户
_connectionString =的connectionS
公共IDataStore获得()
_database =新的数据存储(_userId,_connectionString);
保护覆盖无效DisposeCore()
如果(_database!= NULL)_database.Dispose();
}} 这些类必须在使用运行时注入的构造函数的参数。到目前为止好,一切都很正常! 当我们到迁移问题就出现了:因为我的数据存储上下文类没有默认构造函数,我需要提供 IDbContextFactory< T> 使得code首先迁移可以实例吧: 公共类MigrationDataStoreFactory:IDbContextFactory<数据存储>{
公共数据存储上创建()
//需要注入的连接字符串,所以我们可以把它传递给这个构造
返回新的数据存储(0,“CONNECTION_STRING_NEEDED_HERE”);
}} 问题是,我想不通我怎么能注入连接字符串到这个班。我不能像这样的连接字符串参数来创建一个新的构造: 公共类MigrationDataStoreFactory:IDbContextFactory<数据存储>{
公共字符串_connectionString {搞定;组; }
公共MigrationDataStoreFactory(字符串的connectionString)
_connectionString =的connectionS
公共数据存储上创建()
返回新的数据存储(0,新DateTimeProvider(()=> DateTime.Now),_connectionString);
}} 如果我这样做,我得到了以下异常在运行时抛出迁移:
[出现InvalidOperationException:上下文工厂类型“MigrationDataStoreFactory'必须具有公共默认构造函数。]
System.Data.Entity.Infrastructure.DbContextInfo.CreateActivator()326
System.Data.Entity.Infrastructure.DbContextInfo..ctor(类型contextType,DbProviderInfo modelProviderInfo,AppConfig的配置,DbConnectionInfo connectionInfo)+106
System.Data.Entity.Infrastructure.DbContextInfo..ctor(类型contextType)+52
System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration配置的DbContext usersContext)+202
System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration配置)+66
System.Data.Entity.MigrateDatabaseToLatestVersion`2.InitializeDatabase(TContext上下文)+50
//截断堆栈跟踪,但你的想法 除此之外,这个类不被实例化统一无妨;它似乎只是由公约code首先迁移莫名其妙地叫,所以即使我能做到,它不会真正帮助... 一切工作正常,如果我硬code该方法中的连接字符串,但我并不想这样做,原因是显而易见的。谁能帮助吗?解决方案 下面是我最终使用的方法,使用自定义 IDatabaseInitializer< T>
code从,该帮了我很多。首先,我们添加一个构造函数的数据存储类(的DbContext ),它不需要连接字符串参数 公共类数据存储:的DbContext,IDataStore{
公众诠释用户名{搞定;私人集; }
//这是由工厂类调用构造函数
//如果它没有连接字符串初始化参数
公共数据存储(INT用户id)
用户名=用户
公共数据存储(INT userid,字符串的connectionString):基地(的connectionString)
用户名=用户
公共虚拟IDbSet&使用者>用户{搞定;组; }
code这里//休息} 然后我们做同样的工厂类: 公共类DataStoreFactory:一次性,IDataStoreFactory{
私人数据存储_
私人诠释_userId;
私人字符串_connectionS
//这是将由被称为构造
// MigrationDataStoreFactory类
公共DataStoreFactory(INT用户id)
_userId =用户
公共DataStoreFactory(INT userid,字符串的connectionString)
_userId =用户
_connectionString =的connectionS
公共IDataStore获得()
//如果我们有一个连接字符串,建设我们的语境有了它,
//如果没有,使用新的构造
如果(_connectionString!= NULL)
_database =新的数据存储(_userId,_dateTimeServices,_connectionString);
_database =新的数据存储(_userId,_dateTimeServices);
保护覆盖无效DisposeCore()
如果(_database!= NULL)_database.Dispose();
}} 这是自定义初始code: 公共类MigrateDatabaseToLatestVersionWithConnectionString< TContext,TMigrationsConfiguration> :IDatabaseInitializer< TContext>
其中,TContext:的DbContext
其中,TMigrationsConfiguration:DbMigrationsConfiguration< TContext&中新(){
私人只读DbMigrationsConfiguration _
公共MigrateDatabaseToLatestVersionWithConnectionString()
_config =新TMigrationsConfiguration();
公共MigrateDatabaseToLatestVersionWithConnectionString(字符串的connectionString)
//设置为TargetDatabase迁移使用附带的连接字符串
_config =新TMigrationsConfiguration {
TargetDatabase =新DbConnectionInfo(的connectionString,
“System.Data.SqlClient的”)
公共无效InitializeDatabase(TContext上下文)
//更新包含正确的连接字符串配置的迁移
DbMigrator dbMigrator =新DbMigrator(_config);
dbMigrator.Update();
}} 我们的自定义上下文工厂(这仅是有史以来code首先迁移的称呼)现在可以使用数据存储构造函数的进行不的需要连接字符串: 公共类MigrationDataStoreFactory:IDbContextFactory<数据存储>{
公共数据存储上创建()
返回新的数据存储(0);
}} 只要我们设置数据库初始化到我们自定义的初始化和连接字符串中传递,迁移将使用(这在我的情况下,的Global.asax 完成)正确的连接:
Database.SetInitializer<数据存储>(新MigrateDatabaseToLatestVersionWithConnectionString<数据存储,MyMigrationsConfiguration>(INJECTED_CONNECTION_STRING_HERE)); 希望一切是有道理的,随时要求澄清的意见。
本文地址: &
扫一扫关注官方微信}

我要回帖

更多关于 ef dbcontext 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信