删除时,是否可以阻止 EFCore 更改实体的状态?

Can I stop EFCore from altering my Entity's state when I delete?

提问人:Peter Morris 提问时间:11/16/2023 最后编辑:Peter Morris 更新时间:11/17/2023 访问量:144

问:

我有以下典型的父/子类,此外,我的所有域实体都来自一个类,该类具有返回所属对象的方法。EntityBase

public abstract class EntityBase
{
    public abstract EntityBase GetRoot();
}

public class Parent : EntityBase
{
  private readonly List<Child> _children = new();
  public IReadOnlyList<Child> Children => _children.AsReadonly();
  
  public void RemoveChild(Child child)
  {
    _children.Remove(child);
  }
  
  public override GetRoot() => this;
}

public class Child : EntityBase
{
  public Parent Parent { get; init; }
  public string Name { get; set; } = "";
  
  public override GetRoot() => Parent;
}

如果我的 DbContext 中有一些代码可以遍历所有修改的实体,请调用它们,以确保它们的根(即父)状态设置为如果是这样,以便我有一个中心点来检查数据库更新冲突。GetRoot()EntityEntryModifiedUnchanged

这适用于修改,但是当我调用并且我的 DbContext 尝试保存更改时,我的代码会调用已删除的子对象并接收,而不是从 Db 获取的父对象。parent.RemoveChild(parent.Children[0])GetRootnull

似乎仅仅执行以获取已修改条目的列表就会改变我的属性的状态。ChangeTracker.EntriesChild.Parent

有没有办法在不发生这种情况的情况下获得列表?ChangeTracker.Entries

这是我之前在我的 .SaveChangesAsyncApplicationDbContext

private void EnsureModifiedEntitiesAggregateRootsAreUpdated(EntityEntry[] modifiedEntries)
{
    foreach (var entry in modifiedEntries)
    {
        if (entry.State != EntityState.Unchanged)
        {
            var entity = (EntityBase)entry.Entity;

            // THIS NEXT LINE ALWAYS RETURNS NULL!
            var aggregateRoot = entity.GetAggregateRoot();

            EntityEntry<EntityBase> aggregateRootEntry = Entry(aggregateRoot);

            if (aggregateRootEntry.State == EntityState.Unchanged)
            {
                aggregateRootEntry.State = EntityState.Modified;
            }
        }
    }
}

我的应用代码可以做到这一点

  1. 获取父项并用于检索子项.Include
  2. parent.Items.RemoveAt(0);
  3. SaveChangesAsync
C# 实体框架核心

评论

0赞 Poul Bak 11/16/2023
不应该是 ?_child.AsReadonly()_children.AsReadonly()
0赞 Gert Arnold 11/16/2023
您可以先将要删除的子项标记为已修改,然后再标记为已删除。但这不是太贵了吗?我的意思是,如果一个子项只被修改,那么仅仅检查该记录是否有并发修改还不够吗?我可以想象,如果添加/删除了节点,您想检查整个树。
0赞 Peter Morris 11/16/2023
@GertArnold 多表聚合的根用作中心冲突锁定点。因此,将子项添加到父项也会保存父项,以确保没有两个人可以同时更改聚合。例如,在添加 PurchaseOrderLine 时保存 PurchaseOrder。
0赞 Gert Arnold 11/16/2023
是的,我明白。但我认为当树结构没有改变时,没有必要修改根。然后,我认为对单个记录进行标准并发检查就足够了。
0赞 Steve Py 11/17/2023
一个因素可能是您删除孩子的方式。您是从它的父级执行此操作,还是只是从 DbContext 中提取子级并将其从 DbSet 中删除?如果是后者,您可以尝试在加载子项时将其删除。.Include(x => x.Parent)

答: 暂无答案