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

如何添加自定义EntityState枚举?软删除特例处理咨询

实现区分软删除与硬删除的自定义实体状态

问题背景

我项目里用了软删除机制,逻辑是检测EntityState.Deleted的实体,给DeletedAt字段赋值当前时间,再把实体状态改成Modified。但现在有一张表需要直接硬删除数据行,不想走软删除流程,所以想加个新的实体状态来区分两种删除操作,该怎么实现?


解决方案

系统自带的EntityState枚举是密封的没法直接扩展,不过我们可以通过自定义状态枚举+实体标记接口的方式来实现需求,一步步来:

1. 定义自定义实体状态枚举

先做一个扩展枚举,补充硬删除的状态选项:

public enum CustomEntityState
{
    Unchanged = EntityState.Unchanged,
    Added = EntityState.Added,
    Modified = EntityState.Modified,
    Deleted = EntityState.Deleted,
    Detached = EntityState.Detached,
    // 新增用于标记硬删除的状态
    HardDeleted
}

2. 创建标记接口标识硬删除实体

给需要硬删除的表对应的实体类实现这个空接口,方便后续快速识别:

// 空接口,仅用作标记
public interface IHardDeletable
{}

// 举个例子:你的硬删除表实体
public class TemporaryData : IHardDeletable
{
    // 实体属性...
    public int Id { get; set; }
    public string Content { get; set; }
}

3. 修改软删除逻辑,区分处理两种删除

这里提供两种实用的实现方式,你可以根据场景选:

方式一:基于接口标记自动区分

适合固定需要硬删除的实体,修改你原来的软删除代码:

var allEntries = ChangeTracker.Entries().ToList();

// 只给非硬删除标记的实体执行软删除逻辑
var softDeleteEntries = allEntries
    .Where(e => e.State == EntityState.Deleted && !e.Entity.GetType().IsAssignableTo(typeof(IHardDeletable)))
    .ToList();

softDeleteEntries.ForEach(e => 
{
    try 
    {
        e.Property("DeletedAt").CurrentValue = DateTime.Now;
        e.State = EntityState.Modified;
    } 
    catch (Exception) 
    { 
        // 可根据需求调整:比如捕获没有DeletedAt字段的实体异常,直接跳过或抛出提示
    }
});

// 实现了IHardDeletable的实体,EF会自动执行真正的DELETE语句,不需要额外处理
方式二:使用自定义状态手动指定

适合同一个实体可能需要两种删除方式的场景,先在删除实体时标记自定义状态:

// 删除时手动标记为硬删除
var targetEntity = dbContext.TemporaryData.Find(123);
// 用EF的Tag属性存储标记,也可以自己维护一个字典
dbContext.Entry(targetEntity).Tag = "HardDelete";
dbContext.Remove(targetEntity);

然后修改处理逻辑:

var deletedEntities = ChangeTracker.Entries().Where(e => e.State == EntityState.Deleted).ToList();

deletedEntities.ForEach(e => 
{
    // 判断是否标记为硬删除,是的话跳过软删除逻辑
    if (e.Tag == "HardDelete")
    {
        return;
    }

    try 
    {
        e.Property("DeletedAt").CurrentValue = DateTime.Now;
        e.State = EntityState.Modified;
    } 
    catch (Exception) 
    { 
        // 异常处理逻辑
    }
});

4. 注意事项

  • 如果用接口标记的方式,建议给所有软删除实体统一实现一个ISoftDeletable接口,里面包含DeletedAt属性,这样可以避免catch块的通用异常捕获,更精准
  • 自定义状态的方式更灵活,但需要开发者在删除时明确标记,避免遗漏
  • 记得把这段逻辑放到重写的SaveChanges/SaveChangesAsync方法里,确保每次保存时都会触发

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:11:32