C#递归方法重复调用时重复插入ChangeLog数据求助
问题分析与修复方案
你的重复插入问题核心源于三个关键逻辑漏洞:
- 从GitLab API获取的
ChangeLogData尚未插入数据库,Id字段为空或为默认值,用pc.Id == cld.Id做过滤完全无效——新数据的数据库自增ID还未生成,根本无法与已有记录匹配。 - 递归过程中传递的
previousChangelog始终是初始的旧数据集合,没有包含递归时新插入的记录,导致后续调用仍会把已插入的数据判定为新数据。 - 开头的版本检查逻辑不准确:仅判断当前版本是否存在任意一条变更记录就终止处理,但实际场景中可能该版本下还有未插入的记录,或者这个判断逻辑本身不符合批量插入的需求。
修复步骤与代码示例
1. 改用GitLab原生唯一标识过滤
找到ChangeLogData中来自GitLab的唯一字段(比如CommitHash、GitLabCommitId这类Git返回的全局唯一值),用这个字段替代数据库自增Id做存在性判断——这是确保过滤有效的核心前提。
2. 递归时更新已存在记录集合
每次插入新数据后,将其合并到已存在的记录列表中,传递给后续递归调用,确保后续判断能覆盖所有已插入的内容。
3. 调整递归逻辑顺序
先处理后续版本并更新已存在记录集合,再处理当前版本,避免遗漏新插入的数据。
修改后的代码:
private async Task PopulateChangeLogDataEntityRecursive(IEnumerable<AppVersionData> versions, IReadOnlyList<ChangeLogData> existingChangelogs) { var currentAppVersion = versions.FirstOrDefault(); if (currentAppVersion == null) { return; } var previousVersions = versions.Skip(1); // 先处理后续版本,同步更新已存在的记录集合 var updatedExistingChangelogs = new List<ChangeLogData>(existingChangelogs); await PopulateChangeLogDataEntityRecursive(previousVersions, updatedExistingChangelogs); var previousAppVersion = previousVersions.FirstOrDefault(); if (previousAppVersion != null) { var changeLogDataList = await _gitLabClient.GetChangeLogData(previousAppVersion.Version, currentAppVersion.Version); foreach (var changeLogData in changeLogDataList) { changeLogData.AppVersionId = currentAppVersion.Id; } // 替换为你实际使用的GitLab唯一标识字段(比如CommitHash) var newChangeLogs = changeLogDataList .Where(cld => !updatedExistingChangelogs.Any(pc => pc.CommitHash == cld.CommitHash)) .ToList(); if (newChangeLogs.Any()) { await _repository.BulkInsertAsync(newChangeLogs); // 将新插入的记录加入已存在集合,供后续递归判断使用 updatedExistingChangelogs.AddRange(newChangeLogs); } } }
额外建议
- 给GitLab唯一标识字段添加数据库唯一约束,从底层防止重复插入,这是最后一道可靠防线。
- 如果你的
ChangeLogData实体还没有存储GitLab的唯一标识,需要先修改实体类和数据库表,添加对应的字段(比如CommitHash)——这是解决问题的必要前提。
内容的提问来源于stack exchange,提问作者varde
相关产品推荐
相关产品推荐

