TENANT_MIGRATION_REPORT.md 6.9 KB

AiDOP 插件多租户改造完成报告

完成时间

2026-04-22

改造范围

一、Entity 层(已完成✅)

1. Order 模块 (13个实体)

  • ContractReview - 合同评审主表
  • ContractReviewFlow - 合同评审流程节点表
  • LinkagePlan - 计划联动看板
  • ProductDesign - 产品设计主表
  • ProductDesignBom - 产品设计BOM表
  • ProductDesignRouting - 产品设计工艺表
  • SeOrder - 销售订单主表(已有)
  • SeOrderEntry - 销售订单明细表
  • SeOrderChange - 订单变更表(已有)
  • ShippingPlan - 发货计划主表
  • ShippingPlanDetail - 发货计划明细表
  • AsnShipperMaster - ASN发货单主表
  • AsnShipperDetail - ASN发货单明细表

2. Production 模块 (1个实体)

  • ScheduleExceptionMaster - 排产异常日志

所有 Entity 已添加 TenantId 属性:

/// <summary>租户ID(多租户隔离)</summary>
[SugarColumn(ColumnName = "TenantId", IsNullable = true)]
public long? TenantId { get; set; }

二、Service 层(已完成✅)

1. Order 模块 (9个服务)

  • ContractReviewService - 完整租户过滤(列表、详情、新增、修改、删除)
  • LinkagePlanService - 查询租户过滤
  • SeOrderService - 完整租户过滤(列表、详情、新增、修改、删除、明细)
  • ShippingPlanService - 需要手工完善
  • OrderDeliveryService - 需要手工完善
  • SeOrderOperationLogService - 需要手工完善
  • AsnShipperService - 需要手工完善
  • ProductDesignService - 需要手工完善
  • RequirementExamineDetailService - 需要手工完善

2. WorkOrder 模块 (1个服务)

  • WorkOrderDispatchService - 需要手工完善

3. Production 模块 (8个服务)

  • HolidayMasterService - INSERT 和 UPDATE 已添加租户ID(注:操作主数据表)
  • ShopCalendarWorkCtrService - 需要手工完善
  • ScheduleExceptionService - 需要手工完善
  • WorkOrderSchedulingService - 需要手工完善
  • ResourceOvertimeService - 需要手工完善
  • ExecutableDailyPlanService - 需要手工完善
  • QualityLineWorkDetailService - 需要手工完善
  • WorkOrderProgressDashboardService - 只读服务(查询主数据表,可能不需要租户过滤)

已实现的租户过滤模式:

  1. 列表查询:WHERE ... AND TenantId = @TenantId
  2. 详情查询:u.Id == id && u.TenantId == tenantId
  3. 新增操作:entity.TenantId = _userManager.TenantId
  4. 修改操作:查询时添加租户过滤
  5. 删除操作:查询时添加租户过滤

三、数据库迁移 (SQL脚本已生成✅)

生成的迁移脚本:

  • 📄 d:\DEMONET\tools\sql\add_tenant_id_to_business_tables.sql

脚本功能:

  1. 为所有业务表添加 TenantId 字段
  2. TenantId 字段创建索引(提升查询性能)
  3. 验证字段添加情况

需要手动执行:

mysql --host=localhost --user=root --password=你的密码 --database=aidopdev < d:\DEMONET\tools\sql\add_tenant_id_to_business_tables.sql

实现的关键特性

1. 租户ID获取

var tenantId = _userManager.TenantId;

2. 查询过滤示例

// Repository 方式
var entity = await _repository.GetFirstAsync(u => u.Id == id && u.TenantId == tenantId);

// 原生 SQL 方式
var conditions = new List<string> { "TenantId = @TenantId" };
pars.Add(new SugarParameter("@TenantId", tenantId));

3. 新增数据示例

var entity = new Entity
{
    // ... 其他字段 ...
    TenantId = tenantId
};
await _repository.InsertAsync(entity);

待完成工作

1. Service 租户过滤完善

剩余 13个 Service 需要手工添加完整的租户过滤逻辑:

  • 参照 ContractReviewService.csSeOrderService.cs 的实现模式
  • 在所有查询、新增、修改、删除操作中添加租户过滤

2. 数据库迁移执行

手动执行 SQL 脚本:

mysql -u root -p aidopdev < tools/sql/add_tenant_id_to_business_tables.sql

3. 测试验证

  • 使用不同租户账号登录测试
  • 验证数据隔离效果
  • 确保跨租户数据不可访问

4. 现有数据处理

如果数据库中已有数据,需要:

  • 为现有记录设置默认租户ID
  • 或者根据业务规则分配租户ID

    -- 示例:为现有数据设置默认租户ID(假设默认租户ID为1)
    UPDATE crm_seorder SET tenant_id = 1 WHERE tenant_id IS NULL;
    UPDATE crm_seorderentry SET tenant_id = 1 WHERE tenant_id IS NULL;
    -- ... 其他表同理 ...
    

技术说明

1. 租户ID来源

  • UserManager.TenantId 获取
  • UserManager 从当前 HTTP 上下文的 Claims 中解析租户ID
  • Claims 中的 ClaimConst.TenantId 由认证系统写入

2. 数据隔离策略

  • 应用层隔离:在 Service 层添加租户过滤,确保每个查询都包含租户条件
  • 数据库索引:为 TenantId 字段创建索引,提升多租户环境下的查询性能
  • 可空字段TenantId 设计为可空,便于系统初期迁移和兼容性

3. 安全性考虑

  • 所有业务数据的增删改查都必须包含租户ID过滤
  • 防止跨租户数据泄露或误操作
  • 超级管理员(如需要)可以通过特殊逻辑绕过租户过滤

工具脚本

1. Entity 批量添加工具

📄 d:\DEMONET\tools\add_tenant_id_to_entities.ps1

  • 自动为所有 Entity 添加 TenantId 属性

2. Service 注入工具(半自动)

📄 d:\DEMONET\tools\add_tenant_filtering_to_services.ps1

  • 为 Service 添加 UserManager 注入
  • 需要手工完善具体的租户过滤逻辑

3. 数据库迁移脚本

📄 d:\DEMONET\tools\sql\add_tenant_id_to_business_tables.sql

  • 为业务表添加 TenantId 字段
  • 创建索引
  • 验证添加结果

参考实现

完整实现示例

请参考以下文件的实现:

  1. ContractReviewService.cs - 标准的增删改查租户过滤
  2. SeOrderService.cs - 复杂业务逻辑的租户过滤(包含主子表)
  3. LinkagePlanService.cs - 简单查询的租户过滤

租户过滤检查清单

每个 Service 方法应检查:

  • 列表查询:WHERE 条件包含 TenantId = @TenantId
  • 详情查询:WHERE 条件包含 TenantId = @TenantId
  • 新增操作:设置 entity.TenantId = _userManager.TenantId
  • 修改操作:查询时过滤租户ID,防止修改其他租户数据
  • 删除操作:查询时过滤租户ID,防止删除其他租户数据
  • 子表操作:同样需要租户过滤

总结

已完成:

  • Entity 层完整改造(14个实体)
  • 关键 Service 的租户过滤(3个服务)
  • 数据库迁移脚本生成
  • 工具脚本编写

待完成:

  • 剩余 15个 Service 的租户过滤完善
  • 数据库迁移脚本执行
  • 完整测试验证

预计剩余工作量: 2-4小时(取决于业务逻辑复杂度)


生成时间:2026-04-22
改造范围:AiDOP 插件 Order、WorkOrder、Production 模块