scaffold-dbcontext 命令可反向生成带 dataannotations 的实体类,提取表结构、注释及 ef core 语义(如 databasegenerated、concurrencytoken),配合嵌入式模板生成准确文档;需注意连接字符串、包依赖、null 处理与手动校验。

用 EntityFrameworkCore 的 Scaffold-DbContext 命令生成基础文档最省事
如果你项目已用 EF Core,Scaffold-DbContext 不仅能反向生成实体类,还能顺带导出结构注释——这是生成文档的第一手材料。它默认把数据库表名、列名、主键、外键、是否允许为空等信息映射到 C# 属性的 [Column]、[Required]、[Comment] 等特性里,而这些特性可被后续工具(如 DocFX 或自定义脚本)提取为文档。
常见错误是没加 -DataAnnotations 参数,导致生成的类里没有 [Comment] ——数据库字段的 DESCRIPTION 或 MS_Description 就丢了。另外,SQL Server 用户必须确认连接字符串里包含 Trusted_Connection=true 或完整凭据,否则命令卡住不报错,只输出空结果。
- PowerShell 中执行:
Scaffold-DbContext "Server=.;Database=MyDb;..." Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models -DataAnnotations -Force - PostgreSQL 用户需装
Npgsql.EntityFrameworkCore.PostgreSQL包,并用对应 provider 名(不是SqlServer) - 若提示
The term 'Scaffold-DbContext' is not recognized,说明未安装Microsoft.EntityFrameworkCore.Tools包,或没在 Package Manager Console 里切换到含.csproj的项目目录
用 SqlDataReader.GetSchemaTable() 手动读取元数据时注意 null 值和类型映射
当需要完全可控的文档内容(比如要导出 Excel 或 Markdown 表格),直接查 INFORMATION_SCHEMA 或用 GetSchemaTable() 更可靠。但这个方法返回的 DataTable 里很多列是 object 类型且可能为 null,比如 ColumnName 是 string,但 ColumnDescription 在 SQL Server 中来自 sys.extended_properties,查不到就是 null,不判空会抛 NullReferenceException。
另一个坑是 NumericPrecision 和 NumericScale 对非数值类型(如 varchar)返回 DBNull.Value,不能直接转 int。建议统一用 row["ColumnName"] as string 或 Convert.ToString(row["ColumnDescription"]) 处理。
- 查字段描述的 SQL(SQL Server):
SELECT obj.name AS TableName, col.name AS ColumnName, prop.value AS Description FROM sys.tables obj INNER JOIN sys.columns col ON obj.object_id = col.object_id LEFT JOIN sys.extended_properties prop ON prop.major_id = col.object_id AND prop.minor_id = col.column_id AND prop.name = 'MS_Description' - 用
GetSchemaTable()时,务必先调用reader.Read()再调用reader.GetSchemaTable(),否则返回null - PostgreSQL 需查
pg_class+pg_attribute+pg_description,且objsubid必须为 0(表级)或 >0(字段级),漏判会导致描述错位
DatabaseGeneratedOption.None 和 [Timestamp] 这类特性容易被忽略,但影响文档准确性
EF Core 模型中,[DatabaseGenerated(DatabaseGeneratedOption.Computed)] 表示该字段由数据库计算(如 GETDATE()),[Timestamp] 表示并发标记字段——这些语义不会出现在数据库的 INFORMATION_SCHEMA 里,但对理解字段行为至关重要。如果文档只罗列表结构,却不标出哪些字段是服务端生成、哪些参与乐观并发,开发人员很可能误写 INSERT 语句或漏处理并发冲突。
这类信息只能从 EF Core 模型代码或 ModelBuilder 配置中提取。例如,遍历 model.GetEntityTypes(),再对每个 entity.GetProperties() 检查 property.ValueGenerated 和 property.IsConcurrencyToken。
-
ValueGenerated.OnAdd→ 文档应标注“插入时由数据库生成” -
IsConcurrencyToken == true→ 标注“用于并发控制,更新时需校验” - 若用 Fluent API 配置(如
builder.Property(x => x.Version).IsRowVersion()),则IsConcurrencyToken为true,但ValueGenerated可能是OnAddOrUpdate,二者要合并解读
生成 HTML/Markdown 文档时,别硬编码路径,用 Assembly.GetExecutingAssembly().Location 定位模板文件
多数人写完元数据提取逻辑,就直接 File.WriteAllText("docs/table_users.md", content),结果部署到不同环境时路径错乱。更稳妥的做法是把模板(如 table-template.md)设为 Embedded Resource,运行时用 Assembly.GetExecutingAssembly().GetManifestResourceStream() 加载,避免 I/O 权限或相对路径问题。
另一个易错点是 Markdown 表格对齐:字段名含下划线(如 user_id)会被某些渲染器误判为强调语法,需转义为 user\_id;SQL 关键字(如 order)在表格里不加反引号,可能被误读为格式指令。
- 嵌入资源命名规则:
根命名空间.文件夹.文件名,比如项目默认命名空间是MyApp,模板放在Templates\schema.md,则资源名是MyApp.Templates.schema.md - 生成字段列表时,用
string.Join("\n", columns.Select(c => $"| {c.Name} | {c.Type} | {c.IsNullable ? "✓" : ""} |"))比拼接字符串更安全 - 不要依赖
dotnet publish自动复制.md文件——它们不是编译产物,必须显式设为CopyToPublishDirectory
实际生成文档最难的不是取数据,而是把数据库约束(CHECK、UNIQUE)、索引覆盖列、外键级联行为、以及 EF 中的配置语义,全部对齐到一份人能看懂的表述里。这一步没法全自动,得靠人工核对几条关键表的输出,否则文档看着整齐,用的时候才发现“创建时间”字段明明是 Computed,文档却写成“可插入”。











