如何在MySQL表字段变更时自动更新C#模型类属性?
解决方案
针对你的场景,因为需要强类型模型支持后续业务操作,dynamic或ExpandoObject确实不合适,推荐下面几种靠谱的实现方式:
1. 基于数据库元数据的代码生成工具(最推荐)
直接写一个小工具读取MySQL表结构,自动生成强类型的Questions类,完全满足编译时检查和后续业务操作需求。
实现步骤:
- 新建一个控制台项目,用来生成模型代码
- 连接MySQL,通过
information_schema.columns查询目标表的所有字段信息 - 根据字段类型映射(MySQL→C#)生成类代码,覆盖项目中的模型文件
- 可以把这个工具集成到预构建事件,或者定时运行(比如每周/每月)
核心代码示例:
using MySqlConnector; using System.Text; using System.IO; // 配置信息 var connectionString = "Server=your_server;Database=your_db;Uid=user;Pwd=password;"; var targetTableName = "questions"; var outputFilePath = @"../YourProject/Models/Questions.cs"; using var dbConn = new MySqlConnection(connectionString); dbConn.Open(); // 查询表字段详情 var columns = dbConn.Query<ColumnMetadata>(@" SELECT COLUMN_NAME, DATA_TYPE FROM information_schema.columns WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = @TableName", new { TableName = targetTableName }); // 生成C#类代码 var codeBuilder = new StringBuilder(); codeBuilder.AppendLine("namespace YourProject.Models;"); codeBuilder.AppendLine(); codeBuilder.AppendLine("public class Questions"); codeBuilder.AppendLine("{"); foreach (var col in columns) { // 映射MySQL类型到C#类型,可根据实际情况扩展 var csharpType = col.DataType switch { "bigint" => "long", "int" => "int", "varchar" => "string", "datetime" => "DateTime", _ => "object" }; codeBuilder.AppendLine($" public {csharpType} {col.ColumnName} {{ get; set; }}"); } codeBuilder.AppendLine("}"); // 写入文件 File.WriteAllText(outputFilePath, codeBuilder.ToString()); // 辅助类,用于接收查询结果 public class ColumnMetadata { public string COLUMN_NAME { get; set; } = string.Empty; public string DATA_TYPE { get; set; } = string.Empty; }
运行这个工具后,新增的Question11字段会自动出现在生成的Questions类中,完全是强类型,后续的增删改查、业务逻辑处理都和普通模型类一样。
2. 使用T4模板实时生成模型
如果你用Visual Studio开发,可以用T4模板直接在项目中动态生成模型类,每次更新数据库后,右键模板运行“自定义工具”即可更新模型。
T4模板示例(Questions.tt):
<#@ template language="C#" debug="false" hostspecific="true" #> <#@ assembly name="MySqlConnector" #> <#@ import namespace="MySqlConnector" #> <#@ import namespace="System" #> <#@ output extension=".cs" #> namespace YourProject.Models; public class Questions { <# var connStr = "Server=your_server;Database=your_db;Uid=user;Pwd=password;"; var tableName = "questions"; using(var conn = new MySqlConnection(connStr)) { conn.Open(); var columns = conn.Query<dynamic>(@" SELECT COLUMN_NAME, DATA_TYPE FROM information_schema.columns WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = @TableName", new { TableName = tableName }); foreach(var col in columns) { var csharpType = col.DATA_TYPE switch { "bigint" => "long", "int" => "int", "varchar" => "string", "datetime" => "DateTime", _ => "object" }; #> public <#= csharpType #> <#= col.COLUMN_NAME #> { get; set; } <# } } #> }
添加这个模板到项目后,会自动生成对应的Questions.cs文件,数据库新增字段后,右键.tt文件选择“运行自定义工具”就能更新模型。
3. 半动态过渡方案(不推荐)
如果暂时不想生成代码,可以用固定属性+字典存储动态字段的方式,但这种方式没有编译时检查,后续操作会比较繁琐:
public class Questions { public long Id { get; set; } // 存储新增的Question字段 private readonly Dictionary<string, int> _dynamicQuestions = new(); // 通过索引器访问动态字段 public int this[string questionKey] { get => _dynamicQuestions.TryGetValue(questionKey, out var value) ? value : 0; set => _dynamicQuestions[questionKey] = value; } // 从Dapper查询结果转换为模型 public static Questions FromDynamicResult(dynamic dbResult) { var model = new Questions(); var modelProps = typeof(Questions).GetProperties(); var resultType = dbResult.GetType(); // 填充固定属性 foreach (var prop in modelProps) { var resultProp = resultType.GetProperty(prop.Name); if (resultProp != null) { prop.SetValue(model, resultProp.GetValue(dbResult)); } } // 填充动态Question字段 foreach (var resultProp in resultType.GetProperties()) { if (resultProp.Name.StartsWith("Question") && !modelProps.Any(p => p.Name == resultProp.Name)) { model._dynamicQuestions[resultProp.Name] = (int)resultProp.GetValue(dbResult); } } return model; } }
这种方式虽然能兼容新增字段,但访问动态字段只能通过索引器,没有智能提示,序列化、验证等操作都需要额外处理,仅适合临时过渡使用。
内容的提问来源于stack exchange,提问作者Shameel Perayil
相关产品推荐
相关产品推荐

