# 多租户字段名统一完成报告 ## 修正时间 2026-04-22 ## 问题描述 数据库字段名不统一: - 部分表使用 `TenantId`(Pascal命名) - 部分表使用 `tenant_id`(下划线命名) **决策:统一使用 `tenant_id`(小写下划线格式)** ## 已完成的修正 ### 一、Entity 层(✅ 已统一) 修正了 **12个 Entity 文件** 的 `SugarColumn` 属性: ```csharp // 修正前 [SugarColumn(ColumnName = "TenantId", IsNullable = true)] public long? TenantId { get; set; } // 修正后 [SugarColumn(ColumnName = "tenant_id", IsNullable = true)] public long? TenantId { get; set; } ``` **已修正的文件:** 1. ✅ `AsnShipperDetail.cs` 2. ✅ `AsnShipperMaster.cs` 3. ✅ `ContractReview.cs` 4. ✅ `ContractReviewFlow.cs` 5. ✅ `LinkagePlan.cs` 6. ✅ `ProductDesign.cs` 7. ✅ `ProductDesignBom.cs` 8. ✅ `ProductDesignRouting.cs` 9. ✅ `SeOrderEntry.cs` 10. ✅ `ShippingPlan.cs` 11. ✅ `ShippingPlanDetail.cs` 12. ✅ `ScheduleExceptionMaster.cs` **原本正确的文件:** - ✅ `SeOrder.cs` - 原本就是 `tenant_id` - ✅ `SeOrderChange.cs` - 原本就是 `tenant_id` ### 二、Service 层(✅ 已统一) #### 1. ContractReviewService.cs 修正了所有 SQL 查询中的字段名: ```csharp // 修正前 var conditions = new List { "TenantId = @TenantId" }; WHERE BillNo LIKE 'CR{month}%' AND TenantId = @TenantId // 修正后 var conditions = new List { "tenant_id = @TenantId" }; WHERE BillNo LIKE 'CR{month}%' AND tenant_id = @TenantId ``` #### 2. HolidayMasterService.cs 完整添加了租户过滤(之前遗漏): **修正内容:** - ✅ 列表查询:`WHERE h.IsActive = 1 AND h.tenant_id = @TenantId` - ✅ 详情查询:`WHERE RecID = @Id AND tenant_id = @TenantId` - ✅ 新增操作:INSERT 包含 `tenant_id` 字段 - ✅ 修改操作:`WHERE RecID = @Id AND tenant_id = @TenantId` - ✅ 删除操作:`WHERE RecID = @Id AND tenant_id = @TenantId` #### 3. SeOrderService.cs 原本就正确使用 `tenant_id`,无需修改 ✅ ### 三、数据库迁移脚本(✅ 已更新) **更新文件:** `d:\DEMONET\tools\sql\add_tenant_id_to_business_tables.sql` **修正内容:** - 所有 `ALTER TABLE` 语句统一使用 `tenant_id` - 所有索引创建统一使用 `tenant_id` - 验证查询统一使用 `tenant_id` ```sql -- 示例(修正后) ALTER TABLE ado_contract_review ADD COLUMN IF NOT EXISTS tenant_id BIGINT NULL COMMENT '租户ID(多租户隔离)'; CREATE INDEX IF NOT EXISTS idx_tenant_id ON ado_contract_review(tenant_id); ``` ## 字段名规范 ### C# Entity 属性命名 ```csharp // 属性名:Pascal命名(TenantId) public long? TenantId { get; set; } ``` ### 数据库列名映射 ```csharp // 数据库列名:小写下划线(tenant_id) [SugarColumn(ColumnName = "tenant_id", IsNullable = true)] ``` ### SQL 查询中的字段名 ```csharp // SQL 中使用:tenant_id "WHERE tenant_id = @TenantId" ``` ## 验证清单 ### Entity 层验证 ```bash # 检查是否还有 TenantId 作为 ColumnName 的情况 grep -r 'ColumnName = "TenantId"' server/Plugins/Admin.NET.Plugin.AiDOP/ # 应该返回:无结果 ``` ### Service 层验证 ```bash # 检查 SQL 查询中的字段名 grep -r 'TenantId = @TenantId' server/Plugins/Admin.NET.Plugin.AiDOP/Order/ grep -r 'TenantId = @TenantId' server/Plugins/Admin.NET.Plugin.AiDOP/Production/ # 应该返回:无结果(已全部改为 tenant_id) ``` ### 数据库验证 执行迁移脚本后,检查所有表: ```sql SELECT TABLE_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'aidopdev' AND COLUMN_NAME IN ('TenantId', 'tenant_id') ORDER BY TABLE_NAME, COLUMN_NAME; -- 预期结果:所有字段名都应该是 tenant_id(小写) ``` ## 统一标准 ### 数据库层级 - ✅ **字段名**:`tenant_id`(小写下划线) - ✅ **索引名**:`idx_tenant_id` - ✅ **数据类型**:`BIGINT NULL` - ✅ **注释**:`租户ID(多租户隔离)` ### 应用层级 - ✅ **C# 属性**:`TenantId`(Pascal命名) - ✅ **ORM 映射**:`[SugarColumn(ColumnName = "tenant_id")]` - ✅ **SQL 查询**:使用 `tenant_id` - ✅ **参数名**:`@TenantId`(C# 风格) ## 涉及的表 共 **13张业务表** 已统一为 `tenant_id`: ### Order 模块(11表) 1. `ado_contract_review` - 合同评审主表 2. `ado_contract_review_flow` - 合同评审流程节点表 3. `LinkagePlan` - 计划联动看板 4. `ProductDesign` - 产品设计主表 5. `ProductDesignBom` - 产品设计BOM表 6. `ProductDesignRouting` - 产品设计工艺表 7. `crm_seorder` - 销售订单主表 8. `crm_seorderentry` - 销售订单明细表 9. `ShippingPlan` - 发货计划主表 10. `ShippingPlanDetail` - 发货计划明细表 11. `AsnShipperMaster` - ASN发货单主表 12. `AsnShipperDetail` - ASN发货单明细表 ### Production 模块(1表) 13. `ScheduleExceptionMaster` - 排产异常日志 ### 主数据表(需手动添加字段) 14. `HolidayMaster` - 产线节假日(Service 已支持租户过滤) ## 下一步操作 ### 1. 执行数据库迁移 ```bash mysql -u root -p你的密码 aidopdev < d:\DEMONET\tools\sql\add_tenant_id_to_business_tables.sql ``` ### 2. 为 HolidayMaster 添加字段 ```sql ALTER TABLE HolidayMaster ADD COLUMN IF NOT EXISTS tenant_id BIGINT NULL COMMENT '租户ID(多租户隔离)'; CREATE INDEX IF NOT EXISTS idx_tenant_id ON HolidayMaster(tenant_id); ``` ### 3. 验证字段统一性 ```sql -- 检查所有业务表的 tenant_id 字段 SELECT TABLE_NAME, COLUMN_NAME, COLUMN_TYPE, IS_NULLABLE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = 'aidopdev' AND COLUMN_NAME = 'tenant_id' ORDER BY TABLE_NAME; ``` ## 生成的工具脚本 1. **📄 字段名统一脚本** `d:\DEMONET\tools\fix_tenant_id_column_name.ps1` 2. **💾 数据库迁移脚本(已更新)** `d:\DEMONET\tools\sql\add_tenant_id_to_business_tables.sql` ## 总结 ✅ **已完成:** - Entity 层字段名统一(12个文件) - Service 层 SQL 查询统一(2个服务) - HolidayMasterService 完整租户过滤实现 - 数据库迁移脚本更新 ✅ **统一标准:** - 数据库字段名:`tenant_id`(小写下划线) - C# 属性名:`TenantId`(Pascal命名) - 完全遵循 .NET 和数据库命名规范 📌 **重要提示:** 现在所有代码和脚本都已统一使用 `tenant_id` 作为数据库字段名,可以安全执行数据库迁移! --- 修正时间:2026-04-22 字段名标准:tenant_id(小写下划线格式)