ASP.NET MVC 与 Entity Framework 6.4 插入随机重复项

ASP.NET MVC with Entity Framework 6.4 Inserting Random Duplicates

提问人:rientelfon 提问时间:10/27/2023 最后编辑:marc_srientelfon 更新时间:10/27/2023 访问量:56

问:

我遇到了一个问题,即使用 ASP.NET MVC 4 和 .NET Framework 4.8 的 Entity Framework 6.4.8 将随机插入重复记录 (2-5)。

附件是我的代码的缩写版本,分解为所有多个基本组件。

执行处理答案和保存的过程,这是一次保存所有内容,因此每个答案应该只有 1 个条目

public bool UpdateBusinessQuestionAnswers(BusinessQuestionAnswerServiceViewModel businessQuestionAnswerDto)
{
        bool success = false;

        try
        {
            int applicationId = businessQuestionAnswerDto.ApplicationId;
            int businessId = businessQuestionAnswerDto.BusinessId;
            var dtoAnswers = businessQuestionAnswerDto.BusinessQuestionAnswers;

            foreach (var answer in dtoAnswers)
                 kyEntityProcessor.ProcessAnswers(applicationId, answer.Id, businessId, answer.Response);

            kyGenericRepo.Save();
            success = true;
        }
        catch (Exception ex)
        {
            _logger.Debug(ex);
        }

        return success;
}

kyEntityProcessor -> 函数:ProcessAnswers

public void ProcessAnswers(int applicationId, int questionId, int businessId, string response)
{
    var answer = kyGenericRepo.FindByApp<KpBusinessQuestionAnswer>(applicationId, x => x.QuestionId == questionId).FirstOrDefault();

    if (answer != null)
    {
        answer.Response = response;
        kyGenericRepo.Edit(answer);              
    }
    else if (!string.IsNullOrWhiteSpace(response))
    {                  
        var newAnswer = NewBusinessQuestionAnswer(businessId, applicationId, questionId, response);
        kyGenericRepo.Add(newAnswer);                              
    }                       
}

功能:NewBusinessQuestionAnswer

public KpBusinessQuestionAnswer NewBusinessQuestionAnswer(int? businessId, int? applicationId, int questionId, string response)
{
    var newAnswer = new KpBusinessQuestionAnswer
        {
            AppId = applicationId,
            BusinessId = businessId,
            QuestionId = questionId,
            Response = response,
            IsDeleted = false
        };

    return newAnswer;
}

功能:kyGenericRepo.Add

public T Add<T>(T entity) where T : class
{
    try
    {
        var _dbSet = context.Set<T>();
        context.Entry(entity).State = EntityState.Added;
        return _dbSet.Add(entity);
    }
    catch (Exception ex)
    {
         logger.Debug(ex);
         return null;
    }
}

如您所见,有一个 for 循环可以处理所有问题,并且我已经验证了每个问题 id 只有 1 个实例,因此应该只向数据库表添加 1 个条目。99% 的情况是这种情况,基本上在 308,768 条记录中,我有 5,656 个重复项和总共大约 30 个似乎被复制的唯一问题 ID。因此,在总共 220 个问题中,大约有 30 个问题是随机发生的。

大约 75% 的时间,这些副本上的时间戳完全相同,其余 25% 的时间,它们相差 ~200 毫秒。

数据从 AngularJS 窗体提交到 .NET Framework API,该 API 执行 SQL Server 2014 数据库的保存过程。这也只触发一次,这意味着不会同时向 API 发送重复的提交。

我在初次点击后禁用了提交按钮,这减少了双击提交,但我仍然收到重复项。我的猜测是 EF 或我的代码中发生了一些事情,导致这些重复项继续发生。

任何帮助将不胜感激!

C# sql-server asp.net-mvc-4 实体框架-6 visual-studio-2022

评论

0赞 wenbingeng-MSFT 10/27/2023
为什么不选择一个单独的属性并将其设置为唯一索引呢?如果没有合适的属性,也可以专门添加一个新属性作为唯一索引。然后你去捕捉更新失败错误。
0赞 rientelfon 10/27/2023
@wenbingeng-MSFT 我有点困惑,你的意思是在数据库中还是在代码中?我到底为什么需要这样做?问题是记录在插入数据库时会重复。
0赞 T N 10/29/2023
(没关系。似乎你已经涵盖了那里的可能性。可能是争用条件。是否有可能有人双击提交按钮可能会触发两个单独的过程,这两个过程都找不到现有的答案,因此都在保存新的答案。我的另一个想法是:dtoAnswers 是否可以包含重复的答案,并且在第一个答案被处理为新答案后,第二个答案被处理并且 FindByApp() 检查没有看到(尚未保存的)第一个答案?
0赞 wenbingeng-MSFT 10/30/2023
@rientelfon我的意思是,在插入数据的时候,可以根据插入的数据生成一组数字,然后将其用作数据库中的唯一索引,这样这组数字就会变得唯一。或者,您可以在插入数据之前查询数据库。当然,这会消耗更多的性能。如果返回结果为空,则表示插入成功。
2赞 rientelfon 10/30/2023
@TN我添加了一个检查,以确保没有重复项,以防万一。如果有,它将报告。

答: 暂无答案