2015-06-22 94 views
2

我正在使用实体框架(最新版本 - 我们所说的6.0)和最新的.NET版本(我们所说的版本4.5.1)编写应用程序。使用实体框架代码首先使用动态连接字符串

我面临的问题是我想使用代码优先的方法,因为我非常喜欢它,但应用程序由各种数据库组成。现在,添加迁移和更新数据库不是问题。即使实体框架需要跟踪多个上下文对象,我也知道这个命令。

但是,这里是其中我负责的具体情况:

  • 我使用包含各种用户的通用的“设置”数据库,每个用户都有它特定的设置。每个用户通用的一个设置是数据库连接字符串。

这确实意味着我有一个设置表,其中可以配置5个用户,但每个用户确实需要另一个数据库(但数据库的结构在每个数据库中都是相同的)。我们为什么使用不同的数据库有非常具体的原因,即使模型是相同的,但我不会详细介绍这些。

现在,问题是我需要如何在我的Visual Studio项目中定义我的第二个上下文。我知道在我的DbContext的构造函数中,我可以传递连接字符串,所以在运行时完全没有问题,但是在开发时,我还使用NuGet程序包管理器来管理数据库的迁移。

有没有什么办法可以一次升级所有的数据库(或一次一个),但是通过获取存储在数据库中的连接字符串(因为它取决于用户)?

亲切的问候

+0

我会想到将数据库迁移到单独的进程,但不是在正常执行应用程序期间。这个过程可能需要独占访问数据库。 –

+0

我正在处理某件事情,但这并不完全。也许你对如何用连接字符串而不是连接字符串名称来调用'Database.SetInitializer'有任何想法。 – Complexity

+0

我想你可以用'DbConnection'参数构建'DbContext',你可以像你一样创建f.e.您可以将连接字符串传递给'SqlConnection'构造函数。 –

回答

2

好吧,我设法找到一个解决办法我自己,我与它很高兴。

首先,我将展示应用程序的结构。

我有一个DbContext称为AppServerSettingsContext这是在源代码中定义是这样的:

/// <summary> 
///  Initializes a new instance of the <see cref="AppServerSettingsDataContext"/>. 
/// </summary> 
public AppServerSettingsDataContext() 
    : base("AppServerSettingsDataContext") 
{ } 

该上下文有2层不同的实体(一个用于一个构件,一个用于该特定部件的所有设置) 。

为了能够执行迁移,我需要在应用程序配置文件中有一个ConnectionString,就像我们使用的方式一样。

然后,我有另一个名为AppServerDataContext的上下文。 这有2个构造如下表现:

/// <summary> 
///  Initializes a new instance of the <see cref="AppServerDataContext"/>. 
/// </summary> 
public AppServerDataContext() : 
    this(ConfigurationManager.ConnectionStrings["AppServer"].ConnectionString) 
{ } 

/// <summary> 
///  Initializes a new instance of the <see cref="AppServerDataContext"/>. 
/// </summary> 
/// <param name="connectionString">The full connection string which is used to connect to the database.</param> 
public AppServerDataContext(string connectionString) 
    : base(connectionString) { } 

你会在这我可以指定连接字符串或我加载应用程序配置文件中的连接字符串代码中看到。

你会明白为什么这很重要。

我有DbContext指向配置文件中的连接字符串。这并不是必须的,但我习惯这样工作。因此只有在调用add-migration命令时才会使用连接字符串。这是因为该命令需要数据库检查数据库的当前状态并添加正确的迁移。

现在,我正在使用2个上下文文件处理单个项目,因此NuGet程序包管理器控制台需要一种方法来识别此问题。

因此,下面的命令可以用来:

  1. 启用特定上下文迁移:

    • `PM>启用的迁移-ContextTypeName:-MigrationsDirectory:

这是一个我需要执行两次的命令,每次执行一次XT。

然后,在我的AppServerSettings上下文的Seed方法,我会写下面的代码:

/// <summary> 
///  Runs after upgrading to the latest migration to allow seed data to be updated. 
/// </summary> 
/// <param name="context">Context to be used for updating seed data.</param> 
protected override void Seed(AppServerSettingsDataContext context) 
{ 
    // Creates the Member and assign all the settings which are required for the application to function. 
    context.Members.AddOrUpdate(x => x.Name, new Member("Povlo") 
    { 
     Settings = new List<MemberSettings> 
     { 
      new MemberSettings("DatabaseConnectionString", "Removed for Security Reasons"), 
     } 
    }); 

    // Make sure that for every member, the database is created by using the "MigrateDatabaseToLatestVersion" migration. 
    foreach (var setting in context.Members.Select(member => member.Settings.FirstOrDefault(x => x.Key == "DatabaseConnectionString"))) 
    { 
     using (var appServerContext = new AppServerDataContext(setting.Value)) 
     { 
      var de = new MigrateDatabaseToLatestVersion<AppServerDataContext, AppServer.Configuration>(); 
      de.InitializeDatabase(appServerContext); 

      appServerContext.Database.Initialize(true); 
     } 
    } 
} 

我在这里做的基本上都是第一次创建与给定的连接字符串的成员(也可以是多个)。

然后,在同样的方法中,我有一个foreach循环,它将根据数据库中的连接字符串创建一个上下文。然后在这种情况下,数据库正在升级到最新版本。

这样做的好处是我使用的是代码优先的方法,并且所有的数据库都是最新的版本。

这样做的缺点是所有模型都需要完全相同。