使用Entity Framework Code First和动态连接字符串

时间:2015-06-22 09:13:55

标签: c# sql-server database entity-framework

我正在编写一个使用Entity Framework的应用程序(最新版本 - 我们说的是6.0)和最新的.NET版本(我们说的是4.5.1版本)。

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

但是,这是我正在处理的具体情况:

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

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

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

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

亲切的问候

1 个答案:

答案 0 :(得分: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&GT;启用 - 迁移--ContextTypeName:-MigrationsDirectory:
  2. 这是一个我需要执行两次的命令,每次执行一次。

    然后,在Seed上下文的AppServerSettings方法中,我将编写以下代码:

    /// <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循环,它将根据数据库中的连接字符串创建一个上下文。然后,对于此上下文,数据库将升级到最新版本。

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

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