HuanMengAdmin/admin-client/代码生成逻辑确认报告.md
2025-11-08 15:00:24 +08:00

12 KiB
Raw Permalink Blame History

代码生成逻辑确认报告

一、数据类型一致性检查

1.1 字段类型对照表

字段名 LowCodeTableInfo ColumnMetaConfig 一致性
DisplayName string? string? 一致
Describe string? string? 一致
CsField string? string? 一致
IsTableSelect bool? bool? 一致
IsImageId bool? bool? 一致
IsTableColumnShow bool? bool? 一致
Width string? string? 一致
OrderById int? int? 一致

结论:所有字段类型完全一致,无需类型转换。

二、完整数据流检查

2.1 初始化流程(从数据库加载)

1. 数据库表结构
   ↓
2. TableSchemaCache.GetAllTables()
   返回: List<DbTableInfo>
   ↓
3. DatabaseTableService.GetAllTables()
   - 遍历 DbTableInfo
   - 调用 MergeTableWithConfig()
   ↓
4. MergeTableWithConfig()
   a) 创建 GenDbTableDto基础信息
   b) 从数据库结构创建 LowCodeTableInfo 列表(基础列信息)
   c) 尝试加载配置文件 TableMetaConfig
   d) 如果配置文件存在:
      - 合并表级配置DisplayName, EntityName, Remark, 路径等)
      - 合并列级配置(遍历 TableInfos从 config.Columns 获取配置)
        * DisplayName = columnConfig.DisplayName
        * Describe = columnConfig.Describe ?? columnInfo.Describe
        * CsField = columnConfig.CsField
        * IsTableSelect = columnConfig.IsTableSelect
        * IsImageId = columnConfig.IsImageId
        * IsTableColumnShow = columnConfig.IsTableColumnShow
        * Width = columnConfig.Width ✅ (string → string直接赋值)
        * OrderById = columnConfig.OrderById ✅ (int? → int?,直接赋值)
   ↓
5. 返回 List<GenDbTableDto>(包含所有表和列信息)

检查结果 逻辑正确

2.2 保存流程(用户修改配置)

1. 前端调用 ChangeByTableAsync()
   参数: TableColumnChangeInput {
     TableName: "T_AccountPasswordLogins",
     DataBase: "LiveForum",
     Columns: [
       { ColumnName: "LoginId", DisplayName: "登录ID", Width: "100px", OrderById: 20 }
     ]
   }
   ↓
2. ChangeByTableAsync() 验证参数
   - 验证 TableName 和 DataBase 不为空
   - 验证 Columns 不为空
   - 从内存缓存查找表GetAllTables()
   ↓
3. 更新内存中的列配置
   - 遍历 input.Columns
   - 根据 ColumnName 匹配 existingColumn
   - 使用 WasFieldProvided() 检测字段是否传递
   - 只更新传递的字段:
     * DisplayName: 如果传递 → 更新null = 清空)
     * Describe: 如果传递 → 更新null = 清空)
     * CsField: 如果传递 → 更新null = 清空)
     * Width: 如果传递 → 更新null = 清空)✅
     * IsTableColumnShow: 如果传递 → 更新null = 设置为 null
     * IsTableSelect: 如果传递 → 更新null = 设置为 null
     * IsImageId: 如果传递 → 更新null = 设置为 null
     * OrderById: 如果传递 → 更新null = 设置为 null✅
   ↓
4. SaveTableMetaConfigAsync()
   - 创建 TableMetaConfig
   - 遍历 tableDto.TableInfos
   - 为每个列创建 ColumnMetaConfig
     * DisplayName = column.DisplayName ✅
     * Describe = column.Describe ✅
     * CsField = column.CsField ✅
     * IsTableSelect = column.IsTableSelect ✅
     * IsImageId = column.IsImageId ✅
     * IsTableColumnShow = column.IsTableColumnShow ✅
     * Width = column.Width ✅ (string → string直接赋值)
     * OrderById = column.OrderById ✅ (int? → int?,直接赋值)
   - 保存到 JSON 文件
   ↓
5. 清除缓存
   ClearAllTablesByCache()

检查结果 逻辑正确

2.3 查询流程(前端获取列列表)

1. 前端调用 FindListByTableAsync()
   参数: TableColumnQueryInput {
     TableName: "T_AccountPasswordLogins",
     DataBase: "LiveForum",
     Page: 1,
     Size: 20
   }
   ↓
2. FindListByTableAsync()
   - 从 GetAllTables() 获取所有表(已包含配置合并)
   - 使用 TableName + DataBase 查找目标表
   - 获取 TableInfos列列表已包含配置
   - 应用筛选和分页
   - 返回 PagingView
   ↓
3. 返回的数据包含:
   - Width: "100px" (string) ✅
   - OrderById: 20 (int?) ✅

检查结果 逻辑正确

2.4 代码生成流程

1. 前端调用 GetCodeAsync()
   参数: GenFormDto {
     TableName: "T_AccountPasswordLogins",
     DataBase: "LiveForum",
     Type: "MiaoYu.Models"
   }
   ↓
2. GetCodeByTypeAndTableNameAsync()
   - 调用 GetGenContextDto(genFormDto)
   ↓
3. GetGenContextDto()
   - 调用 GetGenContextDtoByTableName(tableName, dataBase)
   - 从 GetAllTables() 查找表(已包含配置合并)
   - 调用 FillPathByLowCodeTable() 填充路径
   - 返回 GenDbTableDto
   ↓
4. 根据 Type 调用相应的生成方法
   - GenModelAsync() / GenServiceAsync() / GenControllerAsync() 等
   - 使用 Razor 模板渲染
   - 模板中使用 TableInfos列信息包含 Width 和 OrderById

检查结果 逻辑正确

三、字段处理逻辑详细检查

3.1 Width 字段处理

类型string?(在 LowCodeTableInfo 和 ColumnMetaConfig 中都是 string?

保存流程

// LowCodeTableInfoService.ChangeByTableAsync()
if (changedColumn.WasFieldProvided("Width"))
{
    existingColumn.Width = changedColumn.Width;  // string? → string?
}

// SaveTableMetaConfigAsync()
Width = column.Width,  // string? → string?,直接赋值

加载流程

// DatabaseTableService.MergeTableWithConfig()
columnInfo.Width = columnConfig.Width;  // string? → string?,直接赋值

检查结果 逻辑正确,无需类型转换

3.2 OrderById 字段处理

类型int?(在 LowCodeTableInfo 和 ColumnMetaConfig 中都是 int?

保存流程

// LowCodeTableInfoService.ChangeByTableAsync()
if (changedColumn.WasFieldProvided("OrderById"))
{
    existingColumn.OrderById = changedColumn.OrderById;  // int? → int?
}

// SaveTableMetaConfigAsync()
OrderById = column.OrderById,  // int? → int?,直接赋值

加载流程

// DatabaseTableService.MergeTableWithConfig()
columnInfo.OrderById = columnConfig.OrderById;  // int? → int?,直接赋值

检查结果 逻辑正确,无需类型转换

3.3 其他字段处理

字符串字段DisplayName, Describe, CsField

  • 保存直接赋值string? → string?
  • 加载直接赋值string? → string?
  • null 处理:保存时 null = 清空,加载时 null = null

可空值类型字段IsTableSelect, IsImageId, IsTableColumnShow

  • 保存直接赋值bool? → bool?
  • 加载直接赋值bool? → bool?
  • null 处理:保存时 null = 设置为 null加载时 null = null

检查结果 所有字段处理逻辑正确

四、接口调用链检查

4.1 前端完整调用流程

1. 获取数据库列表
   GET /api/CodeGeneration/databases
   → CodeGenerationController.GetDatabasesAsync()
   → CodeGenerationService.GetAllDataSources()
   ✅ 返回所有数据源列表

2. 获取表列表
   POST /api/v1/admin/LowCodeTable/FindList
   → LowCodeTableController.FindListAsync()
   → LowCodeTableService.FindListAsync()
   → DatabaseTableService.GetAllTables()
   ✅ 支持按 DataBase 筛选

3. 获取列列表
   POST /api/v1/admin/LowCodeTableInfo/FindListByTable
   → LowCodeTableInfoController.FindListByTableAsync()
   → LowCodeTableInfoService.FindListByTableAsync()
   → DatabaseTableService.GetAllTables()
   ✅ 使用 TableName + DataBase 查询

4. 保存列配置
   POST /api/v1/admin/LowCodeTableInfo/ChangeByTable
   → LowCodeTableInfoController.ChangeByTableAsync()
   → LowCodeTableInfoService.ChangeByTableAsync()
   → SaveTableMetaConfigAsync()
   → TableMetaConfigService.SaveConfigAsync()
   ✅ 使用 TableName + DataBase 保存

5. 生成代码
   POST /api/CodeGeneration/getCode
   → CodeGenerationController.GetCodeAsync()
   → CodeGenerationService.GetCodeByTypeAndTableNameAsync()
   → GetGenContextDto()
   → GetGenContextDtoByTableName()
   → DatabaseTableService.GetAllTables()
   ✅ 使用 TableName + DataBase 查询

检查结果 所有接口调用链正确

五、边界情况检查

5.1 Width 字段边界情况

场景 保存前 保存后 加载后 结果
正常值 "100px" "100px" "100px"
百分比 "50%" "50%" "50%"
自动 "auto" "auto" "auto"
空值 null null null
空字符串 "" "" ""
未传递 (原值) (保持原值) (保持原值)

检查结果 所有边界情况处理正确

5.2 OrderById 字段边界情况

场景 保存前 保存后 加载后 结果
正常值 20 20 20
零值 0 0 0
空值 null null null
未传递 (原值) (保持原值) (保持原值)

检查结果 所有边界情况处理正确

5.3 配置文件不存在的情况

场景:首次使用,配置文件不存在

流程

  1. MergeTableWithConfig() 尝试加载配置文件
  2. 配置文件不存在,config = null
  3. 跳过配置合并,使用数据库结构的默认值
  4. WidthOrderById 使用默认值null

检查结果 处理正确

5.4 部分列有配置的情况

场景:配置文件中只有部分列的配置

流程

  1. MergeTableWithConfig() 加载配置文件
  2. 遍历 genTable.TableInfos
  3. 对于有配置的列:合并配置(包括 Width 和 OrderById
  4. 对于无配置的列:保持数据库结构的默认值

检查结果 处理正确

六、数据一致性验证

6.1 保存 → 加载一致性

测试场景

  1. 用户修改列配置:Width = "100px", OrderById = 20
  2. 保存到配置文件
  3. 清除缓存
  4. 重新加载

预期结果

  • Width = "100px"
  • OrderById = 20

验证代码

// 保存
Width = column.Width,  // "100px"
OrderById = column.OrderById,  // 20

// 加载
columnInfo.Width = columnConfig.Width;  // "100px"
columnInfo.OrderById = columnConfig.OrderById;  // 20

检查结果 数据一致性正确

6.2 类型一致性验证

验证点

  • LowCodeTableInfo.Widthstring?
  • ColumnMetaConfig.Widthstring?
  • 保存和加载都是直接赋值,无类型转换

检查结果 类型完全一致

七、潜在问题检查

7.1 已修复的问题

问题 1Width 字段类型不一致

  • 修复前ColumnMetaConfig.Widthint?,需要类型转换
  • 修复后ColumnMetaConfig.Widthstring?,直接赋值

问题 2OrderById 字段未持久化

  • 修复前ColumnMetaConfig 中没有 OrderById 字段
  • 修复后ColumnMetaConfig 中添加了 OrderById 字段

问题 3Width 字段加载时未合并

  • 修复前MergeTableWithConfig() 中未处理 Width 字段
  • 修复后MergeTableWithConfig() 中直接赋值 Width

7.2 无潜在问题

经过全面检查,当前逻辑:

  • 数据类型完全一致
  • 保存和加载逻辑正确
  • 边界情况处理完善
  • 数据一致性保证

八、总结

8.1 逻辑正确性确认

所有核心逻辑正确

  1. 数据类型一致性:所有字段类型在各个环节完全一致
  2. 保存流程:正确保存所有可配置字段(包括 Width 和 OrderById
  3. 加载流程:正确加载所有配置字段(包括 Width 和 OrderById
  4. 字段处理:字符串字段和可空值类型字段处理逻辑正确
  5. 边界情况:所有边界情况都有正确的处理逻辑

8.2 关键改进点

  1. Width 字段:从 int? 改为 string?,保留完整格式信息
  2. OrderById 字段:添加到 ColumnMetaConfig,支持持久化
  3. 类型转换:移除了所有不必要的类型转换,直接赋值

8.3 验证建议

建议进行以下测试验证:

  1. 修改 Width 为 "100px",保存后重新加载验证
  2. 修改 Width 为 "50%",保存后重新加载验证
  3. 修改 OrderById 为 20保存后重新加载验证
  4. 修改 Width 为 null保存后重新加载验证
  5. 修改 OrderById 为 null保存后重新加载验证

结论 所有逻辑正确,可以正常使用