唐山网站建设找汉狮,找建筑类工作哪个网站好,鹿泉网站建设,网站建设模板删不掉Ef Core花里胡哨系列(1) SafeDelete、ReadOnly、Audit 安全删除、只读、审计等
在软件设计中#xff0c;软删除是一种常见的数据管理技术#xff0c;用于标记和隐藏被删除的数据#xff0c;而不是永久地从数据库中删除它们。软删除通常通过在数据表中添加一个额外的标志列软删除是一种常见的数据管理技术用于标记和隐藏被删除的数据而不是永久地从数据库中删除它们。软删除通常通过在数据表中添加一个额外的标志列例如IsDeleted来实现。当数据被删除时该标志列被设置为指示删除状态的值通常是true或1而不是直接从数据库中删除数据记录。
使用软删除的主要原因是保留数据的完整性和可追溯性。通过软删除我们可以避免永久删除数据从而避免意外或不可逆的数据丢失。软删除还可以帮助我们满足法律、合规性或审计要求因为我们可以跟踪和记录数据的删除历史。
另一个重要的原因是软删除可以提供更好的用户体验。软删除允许用户恢复被删除的数据而不必联系管理员或支持团队。这对于误删除或需要恢复数据的情况非常有用。
然而软删除也有一些潜在的缺点。首先软删除会增加数据库的存储需求因为被删除的数据仍然存在于数据库中。其次软删除可能会导致查询和性能方面的复杂性因为我们需要在查询中过滤掉已删除的数据。
总之软删除是一种在软件设计中常见的数据管理技术它通过标记和隐藏被删除的数据来保留数据的完整性和可追溯性。它提供了更好的用户体验并满足法律和合规性要求。然而软删除也有一些潜在的缺点需要在设计和实现时加以考虑。
定义约束
我们先定义一个安全删除的接口用于约束对应的实体类。
public interface ISoftDelete
{public bool IsDeleted{get; set;}
}通过重写ef core来实现对实现了该接口的成员进行自动处理
通过读取ef core上下文中追踪的实体如果是继承自ISoftDelete接口说明便不是直接删除数据而是软删除即更新数据将实体对应的IsDeleted标记更改为true随后将状态改为EntityState.Modified即进行更新操作。
public class SampleDbContext(DbContextOptionsSampleDbContext options, IServiceProvider serviceProvider): DbContext(options)
{public override async Taskint SaveChangesAsync(CancellationToken cancellationToken new CancellationToken()){foreach (var entityEntry in ChangeTracker.EntriesIEntity()){if (entityEntry is { Entity: ISafeDelete safeDelete, State: EntityState.Deleted }){safeDelete.IsDeleted true;entityEntry.State EntityState.Modified;}}return await base.SaveChangesAsync(cancellationToken);}}如何查询时自动过滤
我们通过重写OnModelCreating方法来预置一些Ef Core的行为例如HasQueryFilter来预置一个过滤条件如果是继承自ISoftDelete的实体那便需要过滤掉已经软删除的数据。 HasQueryFilter仅可以配置一种过滤且每次查询都会生效。如果有权限相关的管理建议在仓储层通过权限来实现过滤更灵活一些或者可以通过在lambda中使用IgnoreQueryFilters()来忽略过滤例如DbSetTEntity().IgnoreQueryFilters()。 public class SampleDbContext(DbContextOptionsSampleDbContext options, IServiceProvider serviceProvider): DbContext(options)
{protected override void OnModelCreating(ModelBuilder modelBuilder){foreach (var entityType in modelBuilder.Model.GetEntityTypes()){if (typeof(ISafeDelete).IsAssignableFrom(entityType.ClrType)){modelBuilder.Entity(entityType.ClrType).HasQueryFilter(GetFilterExpression(entityType.ClrType));}}base.OnModelCreating(modelBuilder);}private ExpressionFuncIEntity, bool GetFilterExpression(Type type){var parameter Expression.Parameter(type, e);var property Expression.Property(parameter, nameof(ISafeDelete.IsDeleted));var body Expression.Equal(property, Expression.Constant(false));return Expression.LambdaFuncIEntity, bool(body, parameter);}public override async Taskint SaveChangesAsync(CancellationToken cancellationToken new CancellationToken()){foreach (var entityEntry in ChangeTracker.EntriesIEntity()){if (entityEntry is { Entity: ISafeDelete safeDelete, State: EntityState.Deleted }){safeDelete.IsDeleted true;entityEntry.State EntityState.Modified;}}return await base.SaveChangesAsync(cancellationToken);}
}联想扩展
我们通过ISoftDelete约束实现了软删除那么我们可以实现其它什么操作呢
我们可以实现一些基于逻辑的业务操作例如只读或者是审计信息等等。
只读ReadOnly
在软件设计中我们一些表可能是记录型数据是不允许更改的不能简单的从接口上约束操作我们可以实现一个IReadOnly接口来标记对应的实体。
public interface IReadOnly
{}public class SampleDbContext(DbContextOptionsSampleDbContext options, IServiceProvider serviceProvider): DbContext(options)
{public override async Taskint SaveChangesAsync(CancellationToken cancellationToken new CancellationToken()){foreach (var entityEntry in ChangeTracker.EntriesIEntity()){// 模式匹配语法即实体如果继承自 IReadOnly 接口且上下文的状态不是添加或者是无操作即抛出异常不允许该操作if (entityEntry is { Entity: IReadOnly, State: not (EntityState.Added and EntityState.Unchanged) }){throw new NotSupportedException();}}return await base.SaveChangesAsync(cancellationToken);}
}