Blame view

项目文档相关/docs/test-reports/店助工资导入数据未更新问题分析.md 4.26 KB
08d94686   “wangming”   优化工资相关服务类和DTO类,增强...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
  # 店助工资导入数据未更新问题分析
  
  ## 问题描述
  
  用户反馈:ID为`780436744116897029`的记录导入后数据没有改变。
  
  ## 测试结果
  
  ### 导入测试
  - **测试文件**: `店助工资_20260113143944.xlsx`
  - **导入结果**: 成功 36 条,失败 0 条,跳过 0 条
  - **状态码**: 200
  - **接口响应**: 正常
  
  ### 数据库记录状态
  - **记录ID**: `780436744116897029`
  - **员工姓名**: 刘雨佳
  - **门店名称**: 绿纤双流店
  - **锁定状态**: `F_IsLocked = 0` (未锁定)
  - **确认状态**: `F_EmployeeConfirmStatus = 0` (未确认)
  - **更新时间**: `2026-01-12T16:38:42.000Z` (导入测试时间为2026-01-13)
  
  ## 问题分析
  
  ### 代码逻辑
  
  `LqAssistantSalaryService.cs` 的导入代码来看:
  
  ```csharp
  // 第1126行
  var entity = existing ?? new LqAssistantSalaryStatisticsEntity { ... };
  
  // 如果existing不为null,entity和existing指向同一个对象
  // 然后修改entity的属性值
  entity.StoreName = storeName;
  entity.EmployeeName = employeeName;
  // ... 其他字段赋值
  
  // 第1233行
  entity.UpdateTime = DateTime.Now;
  
  // 第1234行
  if (existing != null) recordsToUpdate.Add(entity);
  ```
  
  ### SqlSugar Updateable 行为
  
  SqlSugar的`Updateable`方法默认只更新**有变化的字段**。如果实体对象的所有字段值与数据库中的值完全相同,SqlSugar可能不会执行任何SQL更新操作。
  
  ### 可能的原因
  
  1. **数据完全相同**: Excel中的所有字段值与数据库中的值完全相同,导致SqlSugar认为没有变化,不执行更新
  2. **UpdateTime未生效**: 虽然代码设置了`entity.UpdateTime = DateTime.Now`,但如果其他所有字段都相同,SqlSugar可能仍然不执行更新(这是一个潜在的SqlSugar行为问题)
  3. **实体对象引用问题**: 由于`entity = existing`,实体对象来自数据库查询,SqlSugar可能使用原始值进行比较
  
  ## 解决方案
  
  ### 方案1:强制更新所有字段(推荐)
  
  使用`UpdateColumns`明确指定要更新的字段,确保所有字段都被更新:
  
  ```csharp
  if (recordsToUpdate.Any())
  {
      await _db.Updateable(recordsToUpdate)
          .UpdateColumns(it => new
          {
              it.StoreName,
              it.EmployeeName,
              it.Position,
              it.StoreTotalPerformance,
              it.StoreBillingPerformance,
              // ... 列出所有需要更新的字段
              it.UpdateTime
          })
          .ExecuteCommandAsync();
  }
  ```
  
  ### 方案2:使用IgnoreColumns排除不需要更新的字段
  
  使用`IgnoreColumns`排除CreateTime等不需要更新的字段,但更新其他所有字段:
  
  ```csharp
  if (recordsToUpdate.Any())
  {
      await _db.Updateable(recordsToUpdate)
          .IgnoreColumns(x => x.CreateTime)
          .IgnoreColumns(x => x.CreateUser)
          .ExecuteCommandAsync();
  }
  ```
  
  ### 方案3:创建新实体对象(不推荐,性能较差)
  
  不使用existing对象,而是创建新的实体对象:
  
  ```csharp
  if (existing != null)
  {
      entity = new LqAssistantSalaryStatisticsEntity
      {
          Id = existing.Id,
          StoreId = existing.StoreId,
          EmployeeId = existing.EmployeeId,
          StatisticsMonth = existing.StatisticsMonth,
          // ... 复制所有字段
      };
  }
  ```
  
  ## 建议
  
  1. **立即修复**: 使用方案1(UpdateColumns)或方案2(IgnoreColumns)确保导入时所有字段都被更新
  2. **验证数据**: 检查Excel中的数据是否真的与数据库中的数据不同
  3. **日志记录**: 添加日志记录,记录每次导入时实际更新的记录数和字段变化
  4. **统一处理**: 检查其他工资服务的导入代码,确保它们也使用相同的更新策略
  
  ## 相关代码位置
  
  - **文件**: `netcore/src/Modularity/Extend/NCC.Extend/LqAssistantSalaryService.cs`
  - **方法**: `ImportSalaryFromExcel`
  - **关键代码行**: 第1126行(entity赋值)、第1233行(UpdateTime设置)、第1251行(批量更新)
  
  ## 参考实现
  
  可以参考`LqSalaryExtraCalculationService.cs`中的实现,它使用了`UpdateColumns`来明确指定要更新的字段:
  
  ```csharp
  await _db.Updateable(uniqueEntitiesToUpdate)
      .UpdateColumns(it => new
      {
          it.BaseRewardPerformance,
          it.CooperationRewardPerformance,
          // ... 明确列出要更新的字段
      })
      .ExecuteCommandAsync();
  ```