我想使用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这样向数据库发送查询:
显然它将引发ForeignKey异常。
有什么方法可以强制EF Core执行查询,以便我编写代码?
答案 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调用来进一步优化。此选项是用于处理大量项目或“大”实体的优化,否则将导致整个网络上的大量数据。