我希望有人能够帮助我,因为我似乎完全陷入困境。
对于我们公司即将开展的项目,我们希望使用Entity Framework 5和代码优先方法。我玩了一会儿,每当我尝试在我们现有的库中使用EF时,我都失败了,因为看起来EF很大程度上依赖于现有的app.config。
在我们公司,我们有一个内部数据库库,允许我们利用MEF(托管扩展性框架)的优势连接到各种数据源和数据库技术,用于数据库提供程序。我只需要传递一些数据库设置,例如主机(或文件),目录,用户凭据和数据库提供程序名称,库会查找相应的插件并返回自定义连接字符串或IDbConnection。 我们希望将此库与EF一起使用,因为它允许我们灵活地使用我们使用的数据库,并在运行时更改数据库。
因此。我看到一个典型的DbContext对象在构造函数中没有参数。它会自动在app.config中查找相应的连接字符串。我们不喜欢这样的东西所以我改变了默认构造函数来获取一个DbConnection对象,该对象被传递给DbContext基类。没有交易。
代码优先模型更改时出现问题。 EF会自动注意到这一点并查找迁移类/配置。但是:典型的迁移类需要上下文的默认无参数构造函数!真可惜!
因此,我们使用IDbContextFactory接口构建自己的迁移类。但同样,这个IDbContextFactory似乎也需要一个无参数构造函数,否则我无法添加迁移或更新数据库。
此外,我创建了自己的数据迁移配置程序,我传递了上下文,也是目标数据库。问题在于:无论我尝试什么,它都找不到任何迁移类。
我完全陷入困境,因为似乎使用EF的唯一方法是在app.config中保存连接字符串。这是愚蠢的,因为我们需要在运行时更改数据库连接,app.config对于默认用户是只读的!
如何解决这个问题?
答案 0 :(得分:3)
答案在这里提供
https://stackoverflow.com/a/15919627/941240
诀窍是稍微修改默认的MigrateDatabaseToLatestVersion
初始化程序,以便:
DbMigrator
仍然会创建一个新的数据上下文,但会根据初始化程序从您的上下文中复制连接字符串。我甚至可以缩短代码。
这就是:
public class MasterDetailContext : DbContext
{
public DbSet<Detail> Detail { get; set; }
public DbSet<Master> Master { get; set; }
// this one is used by DbMigrator - I am NOT going to use it in my code
public MasterDetailContext()
{
Database.Initialize( true );
}
// rather - I am going to use this, I want dynamic connection strings
public MasterDetailContext( string ConnectionString ) : base( ConnectionString )
{
Database.SetInitializer( new CustomInitializer() );
Database.Initialize( true );
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
public class CustomInitializer : IDatabaseInitializer<MasterDetailContext>
{
#region IDatabaseInitializer<MasterDetailContext> Members
// fix the problem with MigrateDatabaseToLatestVersion
// by copying the connection string FROM the context
public void InitializeDatabase( MasterDetailContext context )
{
Configuration cfg = new Configuration(); // migration configuration class
cfg.TargetDatabase = new DbConnectionInfo( context.Database.Connection.ConnectionString, "System.Data.SqlClient" );
DbMigrator dbMigrator = new DbMigrator( cfg );
// this will call the parameterless constructor of the datacontext
// but the connection string from above will be then set on in
dbMigrator.Update();
}
#endregion
}
客户代码:
static void Main( string[] args )
{
using ( MasterDetailContext ctx = new MasterDetailContext( @"Database=ConsoleApplication801;Server=.\SQL2012;Integrated Security=true" ) )
{
}
using ( MasterDetailContext ctx = new MasterDetailContext( @"Database=ConsoleApplication802;Server=.\SQL2012;Integrated Security=true" ) )
{
}
}
运行此命令将导致根据迁移配置创建和迁移两个数据库。
答案 1 :(得分:0)
它需要一个无参数构造函数才能调用它。您可以做的是在空构造函数中提供默认的DbConntectionFactory
,例如:
public DbContext()
{
IDbContextFactory defaultFactory; //initialize your default here
DbContext(defaultFactory);
}
public DbContext(IDbContextFactory factory)
{
}