实体框架未使用更新的连接字符串

c# database-connection entity-framework-6 multithreading

是否可以更改app.config文件中的连接字符串并让Entity Framework开始使用新值?

我有一个多线程应用程序,其中一个线程充当调度程序。此线程能够接收消息,告知它更改全部或部分连接字符串数据(例如密码更改)。然后,它会更新配置文件以包含新的连接信息,并清除所有池化的数据库连接。这部分都正常工作。

问题是,当调度程序启动一个新线程并且该线程创建一个新的数据库上下文时,将使用旧的连接字符串值创建数据库连接。似乎实体框架在某处保留了此信息的缓存副本。如果我完全关闭并重新启动应用程序它可以正常工作,因为它显然必须从配置文件中读取新值。

我已经看到了其他提出的解决方案,涉及将连接字符串保持为变量并将其传递给上下文构造函数。但是由于调度程序线程没有内部知道它创建的“作业”线程(有些甚至可能不需要数据库访问),这对我来说并不适用。至少没有很多代码更改和我的工作界面的特殊要求。

这是我用来更新文件的代码。正如我所说,这部分正在发挥作用。还有什么我需要做的事情来告诉实体框架有关变化吗?

 // Create new connection string

 SqlConnectionStringBuilder connectionBuilder = new SqlConnectionStringBuilder(ConfigurationManager.ConnectionStrings[CONNECTION_STRING_NAME].ConnectionString);
 connectionBuilder.DataSource = server;
 connectionBuilder.InitialCatalog = database;
 connectionBuilder.UserID = user;
 connectionBuilder.Password = password;

 // Update connection string within config file

 Configuration config = ConfigurationManager.OpenExeConfiguration(Assembly.GetExecutingAssembly().Location);
 ConnectionStringsSection section = (ConnectionStringsSection)config.GetSection("connectionStrings");
 section.ConnectionStrings[CONNECTION_STRING_NAME].ConnectionString = connectionBuilder.ToString();

 // Save changes

 ConfigurationManager.RefreshSection("connectionStrings");
 config.Save();

一般承认的答案

ConfigurationManager.RefreshSection方法的文档确实说(重点是我的):

刷新命名部分, 以便下次检索它时将从磁盘重新读取。

问题是EF6将ConfigurationManager.ConnectionStrings缓存在内部类静态属性中,因此它永远不会刷新。

不幸的是,没有“官方”方式来刷新它。以下是使用反射的暴力破解,因此请自行承担风险:

static readonly Type EF6AppConfigType = typeof(DbContext).Assembly.GetType("System.Data.Entity.Internal.AppConfig");

static readonly PropertyInfo EF6DefaultAppConfig = EF6AppConfigType.GetProperty("DefaultInstance", BindingFlags.Public | BindingFlags.Static);

static readonly FieldInfo EF6ConnectionStrings = EF6AppConfigType.GetField("_connectionStrings", BindingFlags.NonPublic | BindingFlags.Instance);

static void RefreshEF6ConnectionStrings()
{
    EF6ConnectionStrings.SetValue(
        EF6DefaultAppConfig.GetValue(null),
        ConfigurationManager.ConnectionStrings
    );
}

保存更改后只需调用它:

static readonly Type EF6AppConfigType = typeof(DbContext).Assembly.GetType("System.Data.Entity.Internal.AppConfig");

static readonly PropertyInfo EF6DefaultAppConfig = EF6AppConfigType.GetProperty("DefaultInstance", BindingFlags.Public | BindingFlags.Static);

static readonly FieldInfo EF6ConnectionStrings = EF6AppConfigType.GetField("_connectionStrings", BindingFlags.NonPublic | BindingFlags.Instance);

static void RefreshEF6ConnectionStrings()
{
    EF6ConnectionStrings.SetValue(
        EF6DefaultAppConfig.GetValue(null),
        ConfigurationManager.ConnectionStrings
    );
}



许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因
许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因