我想使用 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()
,所以我假设所有删除操作都将在单个事务中执行,当然它们将按以下顺序执行:
- 删除子记录
- 删除父级
但是 EF 像这样向数据库发送查询:
- 删除 parent
- 删除子记录
显然它会抛出 ForeignKey 异常。
有什么方法可以强制 EF Core 执行查询以便我编写代码吗?
最佳答案
在DB级别设置父子关系为级联删除。
一键查询所需数据...
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();
然后只需检查数据并采取相应行动即可。如果没有剩余的 child ,删除父级并让级联处理它。否则,只需从上下文中删除 child 。
if(!data.HasRemainingChildren)
context.Parents.Remove(data.Parent);
else
context.Children.RemoveRange(data.ChildrenToRemove);
对于大型实体,您可以通过仅选择 ID 然后将它们关联到新的实体实例、将它们附加到新的 DbContext,然后发出 Remove/RemoveRange 调用来进一步优化这一点。此选项是处理大量项目或“大”实体的优化,否则会导致大量数据传输。
关于c# - EF Core - 在事务中强制执行命令的优先级,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53259488/