You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EF Core 6偶发重复插入多条相同记录问题求助

解决Razor Pages + EF Core 6表单偶发重复插入问题

问题分析

你遇到的偶发重复插入(几百次提交出现一次),两条记录仅Id和UpdatedDate(相差1秒)不同,核心原因几乎可以确定是重复提交请求:

  • 用户快速连续点击提交按钮
  • 网络波动导致浏览器自动重试未收到响应的请求

解决方案

1. 前端层面:阻止重复点击

点击提交按钮后立即禁用按钮,从源头避免重复提交:

<input type="submit" value="Save" class="btn btn-primary" asp-route-mode="@Model.Mode" 
       style="margin-top:15px; padding:5px;" 
       onclick="this.disabled=true; this.form.submit();" />

或者用更健壮的JS监听表单提交事件:

document.querySelector('form').addEventListener('submit', function() {
    const submitBtn = this.querySelector('input[type="submit"]');
    submitBtn.disabled = true;
    submitBtn.value = 'Saving...';
});

2. 后端层面:实现幂等校验

前端防护可能被绕过,后端需要确保同一请求不会被处理多次,两种常用方案:

方案A:请求唯一令牌校验

  • 在页面生成唯一令牌,通过隐藏域提交:
<input type="hidden" name="RequestToken" value="@Guid.NewGuid().ToString()" />
  • 后端接收后,用缓存记录已处理的令牌(设置合理过期时间):
public async Task<IActionResult> OnPostAsync(string requestToken)
{
    // 检查令牌是否已处理
    if (await _memoryCache.GetStringAsync(requestToken) != null)
    {
        ModelState.AddModelError(string.Empty, "请求已处理,请勿重复提交");
        return Page();
    }
    // 标记令牌已处理,5分钟后过期
    await _memoryCache.SetStringAsync(requestToken, "processed", TimeSpan.FromMinutes(5));

    // 原有保存逻辑
    Rate.UpdatedDate = DateTime.UtcNow;
    _context.MedBAmounts.Add(Rate);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

方案B:业务字段唯一约束

如果业务上NewAmount结合其他关联字段(比如用户ID、关联实体ID)应该唯一,给数据库表添加唯一约束,后端捕获冲突异常:

try
{
    Rate.UpdatedDate = DateTime.UtcNow;
    _context.MedBAmounts.Add(Rate);
    await _context.SaveChangesAsync();
}
catch (DbUpdateException ex)
{
    // 捕获SQL Server唯一约束冲突错误码(2601)
    if (ex.InnerException is SqlException sqlEx && sqlEx.Number == 2601)
    {
        ModelState.AddModelError(string.Empty, "该记录已存在,请勿重复提交");
        return Page();
    }
    throw; // 其他异常正常抛出
}

3. 优化UpdatedDate设置

用DateTime.UtcNow代替DateTime.Now避免时区问题,更推荐让数据库自动生成该字段:

// 实体类配置
public class MedBAmount
{
    // 其他字段
    public DateTime UpdatedDate { get; set; }
}

// 在DbContext的OnModelCreating中配置默认值
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<MedBAmount>()
        .Property(x => x.UpdatedDate)
        .HasDefaultValueSql("GETUTCDATE()");
}

之后后端无需手动设置UpdatedDate,由数据库自动生成,减少代码冗余。

内容的提问来源于stack exchange,提问作者user3496144

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 23:42:51