.Net Core 2.0+SQLite EFCore中删除操作并发检查失效问题
这个问题我之前也碰到过,EF Core在SQLite环境下用[ConcurrencyCheck]处理删除操作的并发确实有小坑——原因是**[ConcurrencyCheck]特性默认只会在更新操作中启用并发检查,删除时不会自动把这个字段纳入WHERE条件**。下面给你几个可行的解决方案:
方案1:改用[Timestamp]特性(推荐)
虽然SQLite没有原生的TIMESTAMP类型,但EF Core支持将TEXT类型的列映射为并发令牌,只需要把[ConcurrencyCheck]换成[Timestamp],同时在DbContext中配置列类型即可。这样EF会自动在更新、删除操作中加入该字段的检查。
步骤:
- 修改模型类的属性:
public class YourEntity { public int Id { get; set; } // 其他属性... [Timestamp] public string? LastUpdated { get; set; } // 直接用字符串类型匹配SQLite的TEXT列 }
- 在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
相关产品推荐
相关产品推荐

