Skip to main content

逻辑删除

逻辑删除是指通过修改数据的某个字段,使其表示为已删除状态,而非真正删除数据。数据仍然保留在数据库中,但查询时不会显示该数据。通常,会添加一个字段来标识数据是否被逻辑删除,例如添加一个“delete_flag”字段,其值为0表示未删除,1表示删除。这样可以在需要时恢复数据。

与物理删除相对应,物理删除指的是从数据库中真正删除数据,即数据存储所用的磁存储区域被清零或擦除,这种情况下删除的数据是无法恢复的。

在Obase中启用逻辑删除非常简单,我们可以使用类型标注或属性标注实现

安装扩展包

  dotnet add Obase.LogicDeletion

类型标注

使用LogicDeletion特性标注哪个属性为逻辑删除:

[LogicDeletion("IdDelete")]
public class Student {
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public bool IdDelete { get; set; }
}

属性标注

使用LogicDeletionMark标记在属性上表示当前字段为逻辑删除字段

public class Student {
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
[LogicDeletionMark]
public bool IdDelete { get; set; }
}

启用逻辑删除

/// <summary>
/// 配置模型
/// </summary>
/// <param name="modelBuilder"></param>
/// <exception cref="NotImplementedException"></exception>
protected override void CreateModel(ModelBuilder modelBuilder)
{
modelBuilder.UseLogicDeletion();
}

使用逻辑删除

在需要使用逻辑删除的时候,我们需要调用RemoveLogically()方法,该方法是立马删除,无需执行SaveChanges()方法。

context.CreateSet<LogicDeletionNoDef>().DeleteLogically(p => p.IntNumber <= 5);

或者

context.LogicDeletionNoDef.DeleteLogically(p => p.IntNumber <= 5);
说明

CreateSet的作用是在对象上下文中创建一个对象集,对象无需在DbContext中存在,使用CreateSet需要注意表是否存在。

无字段使用逻辑删除

在升级项目时,如果旧实体模型中没有逻辑删除字段,我们可以通过无字段逻辑删除来实现这一需求。要使用无字段逻辑删除,我们需要在CreateModel()方法中进行相应的配置。通过这样的配置,框架在执行时会自动向数据库添加逻辑删除字段(自动添加需要设置EnableStructMapping=true,如果数据库存在字段则会跳过),从而实现了逻辑删除的功能。这种方式的优点在于,它不需要对原始模型进行修改,而是在运行时动态添加所需的字段,使得升级过程更加灵活和方便。

protected override void CreateModel(ModelBuilder modelBuilder)
{
//代码配置未定义字段的逻辑删除
var logicDeletionNodef = modelBuilder.Entity<LogicDeletionNoDef>();
logicDeletionNodef.HasKeyAttribute(p => p.IntNumber).HasKeyIsSelfIncreased(false);
//创建逻辑删除扩展
var logicDeletionNodefExt = logicDeletionNodef.HasExtension<LogicDeletionExtensionConfiguration<LogicDeletionNoDef>>();
//当类中未定义逻辑删除字段时 仅需要指定为逻辑删除映射字段
logicDeletionNodefExt.HasDeletionField("IsDelete");
}

查询逻辑删除后数据

在查询数据时,我们希望自动筛选掉被逻辑删除的数据。通过调用上下文的EnableLogicDeletion()方法,我们可以确保查询结果仅包含未被逻辑删除的数据。

 var context = new DbContext();

//未启用过滤
var logicDeletionAnnotationCount = context.CreateSet<LogicDeletionAnnotation>().Count();
var logicDeletionNoDefnCount = context.CreateSet<LogicDeletionNoDef>().Count();

Console.WriteLine($"logicDeletionAnnotationCount:{logicDeletionAnnotationCount}"); //输出结果:10
Console.WriteLine($"logicDeletionNoDefnCount:{logicDeletionNoDefnCount}"); //输出结果:10

context.EnableLogicDeletion();

//启用过滤后查询
logicDeletionAnnotationCount = context.CreateSet<LogicDeletionAnnotation>().Count();
logicDeletionNoDefnCount = context.CreateSet<LogicDeletionNoDef>().Count();

Console.WriteLine($"logicDeletionAnnotationCount:{logicDeletionAnnotationCount}"); //输出结果:0
Console.WriteLine($"logicDeletionNoDefnCount:{logicDeletionNoDefnCount}"); //输出结果:0

恢复逻辑删除的数据

 var context = new DbContext();
context.CreateSet<LogicDeletionAnnotation>().RecoveryLogically(p => p.IntNumber >= 0);