在我的asp.net mvc 5应用程序中,首先使用ef6和数据库方法,我需要为某些实体实现软删除模式。在为实体本身正常工作时,不会更新任何外键连接。 由于我的查询过滤器未返回这些实体,但它们仍在其他表中引用,因此我得到了一些空指针异常。
没有软删除机制,级联上的删除就可以正常工作。
我不想在数据库端使用触发器。
唯一的方法是在删除实体本身之前在控制器中显式删除那些链接的实体吗?
例如: 我有一个用户和一个角色实体。那些与UserRoles表的引用链接在一起。当我删除角色时,也必须删除UserRoles表中的引用。
到目前为止,我已经通过重写SaveChanges方法将删除更改为更新语句。但是我找不到一种方法来通用地找到所有外键来将它们也标记为已删除。
另一个方法是使用IDbCommandTreeInterceptor将删除更改为更新。在这个拦截器中,我可以使用EntityType.NavigationProperties来识别那些对象,但是我无法找到一种方法来获取引用的ID来“删除”它。
我的实体:
public partial class User
{
public int Id { get; set; }
public string name { get; set; }
public int isDeleted { get; set; }
...
}
public partial class Role
{
public int Id { get; set; }
public string name { get; set; }
public int isDeleted { get; set; }
...
}
public partial class UserRole
{
public int Id { get; set; }
public int UserId { get; set; }
public int RoleId { get; set; }
public int isDeleted { get; set; }
...
}
SaveChanges方式:
public override int SaveChanges()
{
ChangeTracker.DetectChanges();
foreach (var entity in ChangeTracker.Entries<ISoftDeletable>())
{
if (entity.State == EntityState.Deleted)
{
entity.State = EntityState.Modified;
entity.Entity.IsDeleted = true;
}
}
return base.SaveChanges();
}
拦截器方式:
public class SoftDeleteInterceptor : IDbCommandTreeInterceptor
{
public const string IsDeletedColumnName = "isDeleted";
public void TreeCreated(DbCommandTreeInterceptionContext interceptionContext)
{
if (interceptionContext.OriginalResult.DataSpace != DataSpace.SSpace)
{
return;
}
if (interceptionContext.Result is DbQueryCommandTree queryCommand)
{
interceptionContext.Result = HandleQueryCommand(queryCommand);
}
if (interceptionContext.OriginalResult is DbDeleteCommandTree deleteCommand)
{
interceptionContext.Result = HandleDeleteCommand(deleteCommand);
}
}
private static DbCommandTree HandleDeleteCommand(DbDeleteCommandTree deleteCommand)
{
var setClauses = new List<DbModificationClause>();
var table = (EntityType)deleteCommand.Target.VariableType.EdmType;
if (table.Properties.All(p => p.Name != IsDeletedColumnName))
{
return deleteCommand;
}
setClauses.Add(DbExpressionBuilder.SetClause(
deleteCommand.Target.VariableType.Variable(deleteCommand.Target.VariableName).Property(IsDeletedColumnName),
DbExpression.FromBoolean(true)));
return new DbUpdateCommandTree(
deleteCommand.MetadataWorkspace,
deleteCommand.DataSpace,
deleteCommand.Target,
deleteCommand.Predicate,
setClauses.AsReadOnly(), null);
}
}
我希望引用已删除实体的UserRole行也将被标记为已删除。