[英]How to delete self referencing entity?
在我當前的項目中,有一個層次結構的文件夾結構保存在數據庫中。 該實體如下:
public class Folder
{
public string Id { get; set; }
public string ParentFolderId { get; set; }
public Folder ParentFolder { get; set; }
public List<Folder> ChildFolders { get; set; } // Relationship property
// Other properties
}
只有根文件夾具有 null 作為ParentFolderId
。 所有其他文件夾都有一個非空的ParentFolderId
。 EFCore 不允許在ParentFolderId
上設置級聯刪除。
刪除文件夾時,我也想遞歸刪除所有子文件夾。 如何實施?
在數據庫上下文中:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Folder>()
.HasOne(e => e.ParentFolder)
.WithMany(e => e.ChildFolders)
.OnDelete(DeleteBehavior.ClientCascade);
}
刪除通話:
public void DeleteFolder(string folderId)
{
var folder = await _db.Folders
.Include(d => d.ParentFolder)
.Include(f => f.ChildFolders)
.FirstOrDefaultAsync(d => d.Id == folderId);
if (folder == null) return;
if (folder.ParentFolderId == null) return null;
_db.Folders.Remove(folder);
_db.SaveChanges();
}
但是,在這種情況下,我只加載層次結構中下一級的子文件夾。 我可以多次調用ThenInclude
,但不能保證到達所有子文件夾。
這是一種通過包含獲取所有子文件夾的方法來實現的方法。 不利的一面是,層次結構中的每一級子文件夾都需要一個 select。 替代方法是 SQL,您可以在其中編寫遞歸查詢以獲取所有要刪除的 ID,然后刪除它們。
public void DeleteFolder(string folderId)
{
var folder = await _db.Folders
.FirstOrDefaultAsync(d => d.Id == folderId);
if (folder == null) return;
var foldersToDelete = await SubFolders(folder.Id);
foldersToDelete.Add(folder);
_db.Folders.RemoveRange(foldersToDelete);
_db.SaveChanges();
}
public async Task<List<Folder>> SubFolders(string folderId)
{
var subFolders = await _db.Folders
.Where(d => d.ParentFolderId == folderId)
.ToListAsync();
var allFolders = new List<Folder>();
foreach(var subFolder in subFolders)
{
allFolders.Add(subFolder);
allFolders.AddRange(await SubFolders(subFolder.Id));
}
return allFolders;
}
如果文件夾中有任何循環,請注意永遠運行(例如文件夾 A 的父級是文件夾 B,文件夾 B 的父級是文件夾 A)
我最終稍微改變了@juharr 的回答。 我沒有創建一堆列表,而是創建一個列表並在遞歸 function 調用之間傳遞它的引用。
這是我的最終代碼:
public void DeleteFolder(string userId, string folderId)
{
var folder = await _db.Folders
.Include(d => d.ParentFolder)
.Include(f => f.ChildFolders)
.FirstOrDefaultAsync(d => d.Id == folderId);
if (folder == null) return;
if (folder.ParentFolderId == null) return;
var foldersToBeDeleted = new List<Folder>();
folder.ChildFolders.ForEach(childFolder => PopulateSubFolder(childFolder.Id, foldersToBeDeleted));
foldersToBeDeleted.Add(folder);
_db.Folders.RemoveRange(foldersToBeDeleted);
_db.SaveChanges();
}
private void PopulateSubFolder(string folderId, ICollection<Folder> foldersToDelete)
{
var folder = _db.Folders
.Include(f => f.ChildFolders)
.FirstOrDefault(f => f.Id == folderId);
if (folder == null) return;
// Add child folders
folder.ChildFolders.ForEach(subFolder => PopulateSubFolder(subFolder.Id, foldersToDelete));
// Add current folder
foldersToDelete.Add(folder);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.