EF Core-强制执行事务中的命令的优先级

时间:2018-11-12 09:46:32

标签: c# entity-framework asp.net-core ef-core-2.1

我想使用EF Core删除数据库中的2组数据。
所有代码均为假设。

数据模型:

class Parent
{
    public int Id { get; set; }
}

class Child
{
    public int Id { get; set; }

    public int ParentId { get; set; }

    public virtual Parent Parent { get; set; }

    public bool Flag { get; set; }
}

假设我要删除所有具有(ParentId = 100)和(flag = false)的[Child]记录,之后如果(child.ParentId = 100).length = 0,那么还要删除父级本身。
因此,这里是服务类:

class Service
{
    public void Command(int parentId)
    {
        Parent parent = GetParent(parentId);
        List<Child> children = GetChildren(parent);

        List<Child> toDelete = children.Where(x => !x.Flag).ToList();
        foreach(var child in toDelete)
        {
            var entry = DbContext.Entry(child);
            entry.State = EntityState.Deleted;
        }

        List<Child> remainChildren = children.Where(x => x.Flag).ToList();
        if (!remainChildren.Any())
        {
            var entry = DbContext.Entry(parent );
            entry.State = EntityState.Deleted;
        }

        SaveChanges();
    }
}

我有多个调用Service.Command方法的方案。
因为我只调用一次SaveChanges(),所以我假设所有删除操作都将在一个事务中执行,当然,它们将按以下顺序执行:

  1. 删除子记录
  2. 删除父级

但是EF这样向数据库发送查询:

  1. 删除父母
  2. 删除子记录

显然它将引发ForeignKey异常。

有什么方法可以强制EF Core执行查询,以便我编写代码?

1 个答案:

答案 0 :(得分:1)

设置父子关系以在数据库级别级联删除。

一键查询所需数据...

var data = context.Parents.Where(p => p.ParentId == parentId)
  .Select(p => new 
  {
    Parent = p,
    ChildrenToRemove = p.Children.Where(c => c.Flag).ToList(),
    HasRemainingChildren = p.Children.Any(c => !c.Flag)
  }).Single();

然后,只需检查数据并采取相应措施即可。如果没有剩余的子代,请删除父代,然后由层叠来照顾。否则,只需从上下文中删除子级即可。

if(!data.HasRemainingChildren)
  context.Parents.Remove(data.Parent);
else
  context.Children.RemoveRange(data.ChildrenToRemove);

对于大型实体,您可以通过仅选择ID,然后将其与新的Entity实例相关联,将它们附加到新的DbContext,然后发出Remove / RemoveRange调用来进一步优化。此选项是用于处理大量项目或“大”实体的优化,否则将导致整个网络上的大量数据。