gpt4 book ai didi

c# - EF Core 级联删除速度?

转载 作者:行者123 更新时间:2023-11-30 15:52:09 25 4
gpt4 key购买 nike

我正在研究一个已建立的(但可变的,假设现有数据在任何更改后仍然存在)代码库并调查一些非常缓慢的删除。到目前为止,我只是成功地让事情变得更糟,所以我们到了。为了避免增加不必要的困惑,我已经撤消了下面我尝试的大部分更改。

有一个数据类 ProductDefinition,它模拟类似于例如文件夹结构:每个 PD(根目录除外)都有一个父级,但就像一个文件夹可以有多个子级一样。

public class ProductDefinition
{
public int ID { get; set; }

// each tree of PDs should have a 'head' which will have no parent
// but most will have a ParentPDID and corresponding ParentPD
public virtual ProductDefinition ParentProductDefinition { get; set; }
public int? ParentProductDefinitionId { get; set; }

public virtual List<ProductDefinition> ProductDefinitions { get; set; }
= new List<ProductDefinition>();

[Required]
[StringLength(100)]
public string Name { get; set; }

// etc. Fields. Nothing so large you'd expect speed issues

}

对应的表已经在Context中明确声明

public DbSet<ProductDefinition> ProductDefinitions { get; set; }

连同在 Context.OnModelCreating 上定义的 Fluent API 关系

modelBuilder.Entity<ProductDefinition>()
.HasMany(productDefinition => productDefinition.ProductDefinitions)
.WithOne(childPd => childPd.ParentProductDefinition)
.HasForeignKey(childPd => childPd.ParentProductDefinitionId)
.HasPrincipalKey(productDefinition => productDefinition.ID);

看起来已经尝试在 ProductDefinitionManager 类中确定删除

public static async Task ForceDelete(int ID, ProductContext context)
{
// wrap the recursion in a save so that it only happens once
await ForceDeleteNoSave(ID, context);
await context.SaveChangesAsync();
}

private static async Task ForceDeleteNoSave(int ID, ProductContext context)
{
var pd = await context.ProductDefinitions
.AsNoTracking()
.Include(x => x.ProductDefinitions)
.SingleAsync(x => x.ID == ID);

if (pd.ProductDefinitions != null && pd.ProductDefinitions.Count != 0)
{
var childIDs = pd.ProductDefinitions.Select(x => x.ID).ToList();

// delete the children recursively
foreach (var child in childIDs)
{
// EDITED HERE TO CORRECTLY REFLECT THE CURRENT CODE BASE
await ForceDeleteNoSave(child, context);
}
}

// delete the PD
// mark Supplier as edited
var supplier = await context.Suppliers.FindAsync(pd.SupplierID);
supplier.Edited = true;

// reload with tracking
pd = await context.ProductDefinitions.FirstOrDefaultAsync(x => x.ID == ID);
context.ProductDefinitions.Remove(pd);
}

目前,上述解决方案“有效”,但是:

a) 需要超过 2 分钟才能完成b) 似乎给 React 前端一个 502 错误(但见上文)。当然,FE 声称是 502

我的主要问题是:有没有办法提高删除速度,例如通过在 FluentAPI 中定义级联删除(我的尝试在尝试应用迁移时遇到了问题)?但我欢迎讨论可能导致 FE 报告 Bad Gateway 的原因。

最佳答案

不幸的是,这是自引用关系,由于“多个级联路径”问题,无法使用级联删除 - SqlServer(可能还有其他)数据库的限制(Oracle 没有此类问题)。

在不支持“多级联路径”的数据库中,最好的处理方式是使用数据库触发器(“而不是删除”)。

但是假设我们想通过 EF Core 中的客户端代码来处理它。问题是如何有效地加载递归树状结构(由于缺乏递归查询支持,EF Core 中的另一个不容易完成的任务)。

您的代码的问题在于它使用了深度优先 算法,该算法会执行大量数据库查询。更合适和高效的方法是使用呼吸优先算法——简单来说,按级别加载项目。这样,数据库查询的数量将是树中的最大深度,这远小于元素的数量。

一种实现方法是从应用初始过滤器的查询开始,然后使用 SelectMany 获取下一个级别(每个 SelectMany 添加一个连接到以前的查询)。当查询没有返回数据时流程结束:

public static async Task ForceDelete(int ID, ProductContext context)
{
var items = new List<ProductDefinition>();

// Collect the items by level
var query = context.ProductDefinitions.Where(e => e.ID == ID);
while (true)
{
var nextLevel = await query
.Include(e => e.Supplier)
.ToListAsync();
if (nextLevel.Count == 0) break;
items.AddRange(nextLevel);
query = query.SelectMany(e => e.ProductDefinitions);
}

foreach (var item in items)
item.Supplier.Edited = true;

context.RemoveRange(items);

await context.SaveChangesAsync();
}

请注意,执行的查询会预先加载相关的 Supplier,因此可以轻松更新它。

收集项目后,只需通过 RemoveRange 方法将它们标记为删除。顺序无关紧要,因为 EF Core 无论如何都会按依赖顺序应用命令。

另一种收集项目的方法是使用上一级别的ID作为过滤器(SQL IN):

// Collect the items by level    
Expression<Func<ProductDefinition, bool>> filter = e => e.ID == ID;
while (true)
{
var nextLevel = await context.ProductDefinitions
.Include(e => e.Supplier)
.Where(filter)
.ToListAsync();
if (nextLevel.Count == 0) break;
items.AddRange(nextLevel);
var parentIds = nextLevel.Select(e => e.ID);
filter = e => parentIds.Contains(e.ParentProductDefinitionId.Value);
}

我更喜欢前者。缺点是 EF Core 会生成一个巨大的表名别名,而且在深度较大的情况下,它可能会遇到一些 SQL 连接数限制。后者没有深度限制,但可能有大 IN 子句的问题。您应该检查哪一个更适合您的情况。

关于c# - EF Core 级联删除速度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55179891/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com