实体框架核心:数据更改后,全局查询过滤器无法正确过滤

时间:2018-09-21 06:30:18

标签: entity-framework-core

我们使用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()查询项目时,它也可以工作,很明显,它也关闭了缓存。

1 个答案:

答案 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;
    }
}