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

.Net Core 2.0+SQLite EFCore中删除操作并发检查失效问题

这个问题我之前也碰到过,EF Core在SQLite环境下用[ConcurrencyCheck]处理删除操作的并发确实有小坑——原因是**[ConcurrencyCheck]特性默认只会在更新操作中启用并发检查,删除时不会自动把这个字段纳入WHERE条件**。下面给你几个可行的解决方案:

方案1:改用[Timestamp]特性(推荐)

虽然SQLite没有原生的TIMESTAMP类型,但EF Core支持将TEXT类型的列映射为并发令牌,只需要把[ConcurrencyCheck]换成[Timestamp],同时在DbContext中配置列类型即可。这样EF会自动在更新、删除操作中加入该字段的检查。

步骤:

  1. 修改模型类的属性:
public class YourEntity
{
    public int Id { get; set; }
    // 其他属性...
    [Timestamp]
    public string? LastUpdated { get; set; } // 直接用字符串类型匹配SQLite的TEXT列
}
  1. 在DbContext的OnModelCreating方法中明确配置并发令牌:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<YourEntity>()
        .Property(e => e.LastUpdated)
        .HasColumnType("TEXT")
        .IsConcurrencyToken(); // 标记为并发令牌
}

配置完成后,EF会自动在删除时生成包含LastUpdated的WHERE条件,当时间戳不匹配时触发DbUpdateConcurrencyException。

方案2:手动构建删除的并发检查条件

如果不想改动特性,你可以手动在删除操作中包含时间戳列的条件,确保只有当时间戳匹配时才执行删除。

示例1:使用ExecuteDelete(EF Core 7+支持)

var targetId = 1;
var currentTimestamp = "2024-05-20T12:34:56"; // 从前端或本地缓存获取的当前时间戳

var deletedCount = await dbContext.YourEntities
    .Where(e => e.Id == targetId && e.LastUpdated == currentTimestamp)
    .ExecuteDeleteAsync();

if (deletedCount == 0)
{
    // 并发冲突,抛出异常或处理业务逻辑
    throw new DbUpdateConcurrencyException("记录已被修改或删除");
}

示例2:先查询再删除(适合旧版本EF Core)

var entity = await dbContext.YourEntities
    .FirstOrDefaultAsync(e => e.Id == targetId && e.LastUpdated == currentTimestamp);

if (entity == null)
{
    throw new DbUpdateConcurrencyException("记录已被修改或删除");
}

dbContext.YourEntities.Remove(entity);
await dbContext.SaveChangesAsync();

方案3:确认触发器逻辑正确

最后再检查一下你的SQLite触发器是否正确,确保插入和更新时都能正确更新时间戳列:

-- 插入时更新时间戳
CREATE TRIGGER IF NOT EXISTS Trigger_YourTable_InsertTimestamp
AFTER INSERT ON YourTable
BEGIN
    UPDATE YourTable SET LastUpdated = DATETIME('now', 'localtime') WHERE Id = NEW.Id;
END;

-- 更新时更新时间戳
CREATE TRIGGER IF NOT EXISTS Trigger_YourTable_UpdateTimestamp
AFTER UPDATE ON YourTable
BEGIN
    UPDATE YourTable SET LastUpdated = DATETIME('now', 'localtime') WHERE Id = NEW.Id;
END;

注意触发器里的LastUpdated要和你的列名一致,DATETIME('now', 'localtime')可以生成带时区的文本时间,确保和EF中存储的格式匹配。

总结一下,方案1是最省心的,因为它利用EF Core的原生并发令牌机制,不需要手动处理每个删除操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:31:52