我们使用Entity Framework Core实现了软删除模式,该模式与this solution非常相似,但是具有可空列“ DeleteDate”而不是IsDeleted标志。如果日期已填满,则该行被视为已删除并过滤掉:
modelBuilder.Entity<TEntity>().HasQueryFilter(e => !EF.Property<DateTime?>(e, "SysDeletedOn").HasValue);
以下代码位将同时更新一项,删除其子元素之一,但在返回的项中,仍将包含已删除的子项。只有对所有项目进行新查询,才能正确过滤子级集合。
public async Task<Item> UpdateItemAsync(ItemDto itemDto)
{
var itemEntity = await _context.Items.SingleOrDefaultAsync(i => i.Id == itemDto.Id);
if(itemEntity != null)
{
return;
}
// Update item's properties here
// ...
foreach (var child in itemDto.Children)
{
// Update child here
// ...
}
foreach (var child in itemDto.RemovedChildren)
{
var childEntity = await itemEntity.SingleOrDefaultAsync(i => i.Id == child.Id);
_context.Remove(childEntity);
}
await _context.SaveChangesAsync();
// Read and return updated item
return await _context.Items.SingleOrDefaultAsync(i => i.Id == itemDto.Id);
}
现在的问题是:进行此更改(删除)后,如何在此方法中获取正确的列表?我是否必须以某种方式清除SaveChangesAsync
和再次读取上下文之间的缓存?
正确返回了项目的常规更新(属性值)。同样,当我用.AsNoTracking()
查询项目时,它也可以工作,很明显,它也关闭了缓存。
答案 0 :(得分:1)
基于链接的解决方案,您还需要分离(即停止跟踪)已成功保存到数据库且带有非空SysDeletedOn
值的所有实体。
public override ...int SaveChanges...
{
OnBeforeSaving();
var result = base.SaveChanges(...);
OnAfterSaving();
return result;
}
private void OnAfterSaving()
{
// you want entries for objects that have the soft delete column
// and whose current value for said property is not null
// this is one way to do it if the property name is always the same
// but it isn't necessarily the most efficient
// (e.g. if there is a base type or interface for the soft delete
// property you can check that)
var entries = this.ChangeTracker.Entries()
.Where( ee => ee.Properties.Any( prop =>
prop.Metadata.Name == "SysDeletedOn"
&& prop.CurrentValue != null ) );
foreach( var entry in entries )
{
// tracked entity is soft deleted and we want to remove it from the context
entry.State = EntityState.Detached;
}
}