ASP.NET MVC5 DB First模式下动态切换数据库及EDMX刷新代码丢失问题
解决EDMX更新后动态切换数据库代码被清除的问题
这问题我之前帮好几个开发者解决过——EDMX的自动生成机制确实会覆盖你手动修改的Db.Context.cs代码,因为每次更新/刷新EDMX时,系统都会基于Db.Context.tt模板重新生成这个文件。直接改生成的文件肯定不行,得从模板或类扩展入手,给你几个靠谱的方案:
方案1:创建Partial Class扩展DbContext(最推荐)
生成的DbContext类本身是partial类型,所以我们可以在单独的文件中写一个同名的partial类,添加动态切换数据库的构造函数或方法。这样即使EDMX更新覆盖了自动生成的文件,我们的自定义代码也不会丢失。
步骤如下:
- 在项目中新建一个类文件(比如命名为
YourDbContext.Dynamic.cs,名字随便取,只要命名空间和自动生成的DbContext一致就行) - 编写partial类代码,添加支持动态数据库的构造函数:
using System.Configuration; using System.Data.SqlClient; namespace YourProjectNamespace // 必须和自动生成的DbContext命名空间一致 { public partial class YourDbContext : DbContext { // 自定义构造函数:传入数据库名称,动态构建连接字符串 public YourDbContext(string targetDbName) : base(BuildDynamicConnectionString(targetDbName)) { // 保持和自动生成类一致的配置(比如禁用懒加载,根据你的实际情况调整) this.Configuration.LazyLoadingEnabled = false; } private static string BuildDynamicConnectionString(string dbName) { // 从Web.config读取基础连接字符串模板 var baseConnString = ConfigurationManager.ConnectionStrings["YourBaseConnStringName"].ConnectionString; // 使用SqlConnectionStringBuilder安全替换数据库名称 var connBuilder = new SqlConnectionStringBuilder(baseConnString); connBuilder.InitialCatalog = dbName; return connBuilder.ToString(); } } }
之后你就可以在代码里这样使用:
using (var db = new YourDbContext("TargetDatabaseName")) { // 执行数据库操作 }
方案2:修改T4模板(从源头解决)
如果想让每次生成的Db.Context.cs都自动包含动态切换的代码,可以直接修改Db.Context.tt模板(这个文件在EDMX文件的下方,展开EDMX就能看到)。
步骤如下:
- 右键点击
Db.Context.tt,选择"编辑" - 在模板中找到生成构造函数的代码块,默认大概是这样:
<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext { public <#=code.Escape(container)#>() : base("name=<#=container.Name#>") { <# if (!loader.IsLazyLoadingEnabled(container)) { #> this.Configuration.LazyLoadingEnabled = false; <# } #> }
- 在这个默认构造函数下方,添加一个自定义的构造函数:
// 新增:支持传入数据库名称的构造函数 public <#=code.Escape(container)#>(string targetDbName) : base(BuildDynamicConnection(targetDbName)) { <# if (!loader.IsLazyLoadingEnabled(container)) { #> this.Configuration.LazyLoadingEnabled = false; <# } #> } private static string BuildDynamicConnection(string dbName) { var baseConn = System.Configuration.ConfigurationManager.ConnectionStrings["<#=container.Name#>"].ConnectionString; var builder = new System.Data.SqlClient.SqlConnectionStringBuilder(baseConn); builder.InitialCatalog = dbName; return builder.ToString(); }
保存模板后,重新生成项目,你会发现Db.Context.cs里已经自动包含了这个构造函数,后续更新EDMX也不会被清除。
方案3:直接传入动态连接字符串(临时应急)
如果不想改模板或加partial类,也可以在使用DbContext时直接构建完整的连接字符串传入:
var targetDbName = "YourTargetDB"; var baseConn = ConfigurationManager.ConnectionStrings["DefaultConn"].ConnectionString; var connBuilder = new SqlConnectionStringBuilder(baseConn); connBuilder.InitialCatalog = targetDbName; using (var db = new YourDbContext(connBuilder.ToString())) { // 数据库操作 }
这个方式不需要修改任何生成的文件,但每次使用都要重复构建连接字符串,适合临时场景,不推荐长期使用。
内容的提问来源于stack exchange,提问作者Sruthi
相关产品推荐
相关产品推荐

