EF Core - 在事务中强制执行命令的优先级
EF Core - Enforce priority in executing commands in a transaction
我想使用 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:
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 执行查询以便我编写代码吗?
将 parent child 关系设置为在数据库级别级联删除。
一键查询所需数据...
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();
然后只需检查数据并采取相应行动即可。如果没有剩余的 children,删除 parent 让 cascade 处理它。否则,只需从上下文中删除 children。
if(!data.HasRemainingChildren)
context.Parents.Remove(data.Parent);
else
context.Children.RemoveRange(data.ChildrenToRemove);
对于大实体,您可以通过仅选择 ID 然后将它们关联到新的实体实例、将它们附加到新的 DbContext,然后发出 Remove/RemoveRange 调用来进一步优化它。此选项是处理大量项目或 "big" 实体的优化,否则会导致大量数据通过网络传输。
我想使用 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:
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 执行查询以便我编写代码吗?
将 parent child 关系设置为在数据库级别级联删除。
一键查询所需数据...
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();
然后只需检查数据并采取相应行动即可。如果没有剩余的 children,删除 parent 让 cascade 处理它。否则,只需从上下文中删除 children。
if(!data.HasRemainingChildren)
context.Parents.Remove(data.Parent);
else
context.Children.RemoveRange(data.ChildrenToRemove);
对于大实体,您可以通过仅选择 ID 然后将它们关联到新的实体实例、将它们附加到新的 DbContext,然后发出 Remove/RemoveRange 调用来进一步优化它。此选项是处理大量项目或 "big" 实体的优化,否则会导致大量数据通过网络传输。