我撰寫了一個簡單的遞回函式來爬上具有 ID 和 PARENTID 的表的樹。
但是當我這樣做時,我收到此錯誤
System.InvalidOperationException: '無法跟蹤物體型別 'InternalOrg' 的實體,因為已經跟蹤了另一個具有相同 {'Id'} 鍵值的實體。附加現有物體時,請確保僅附加一個具有給定鍵值的物體實體。
有沒有另一種方法可以做到這一點,或者可能在一個 LINQ 運算式中完成?
private InternalOrgDto GetInternalOrgDto(DepartmentChildDto dcDto)
{
if (dcDto.InternalOrgId != null)
{
InternalOrg io = _internalOrgRepo.Get(Convert.ToInt32(dcDto.InternalOrgId));
InternalOrgDto ioDto = new InternalOrgDto
{
Id = io.Id,
Abbreviation = io.Abbreviation,
Code = io.Code,
Description = io.Description
};
return ioDto;
}
else
{
//manually get parent department
Department parentDepartment = _departmentRepo.Get(Convert.ToInt32(dcDto.ParentDepartmentId));
DepartmentChildDto parentDepartmenDto = ObjectMapper.Map<DepartmentChildDto>(parentDepartment);
return GetInternalOrgDto(parentDepartmenDto);
}
}
uj5u.com熱心網友回復:
有沒有辦法通過 Linq 從給定的孩子獲得頂級父母?不是我所知道的。您可以遞回地執行類似于您所做的操作,但我建議簡化查詢以避免加載整個物體,直到您獲得所需內容。我從你的代碼中猜測只有頂級上級部門才會有 InternalOrg?否則,此方法將遞回父物件,直到找到父物件為止。這可以加速一點:
private InternalOrgDto GetInternalOrgDto(DepartmentChildDto dcDto)
{
var internalOrgid = dcDto.InternalOrgId
?? FindInternalOrgid(dcDto.ParentDepartmentId)
?? throw new InternalOrgNotFoundException();
InternalOrgDto ioDto = _context.InternalOrganizations
.Where(x => x.InternalOrgId == internalOrgId.Value)
.Select(x => new InternalOrgDto
{
Id = x.Id,
Abbreviation = x.Abbreviation,
Code = x.Code,
Description = x.Description
}).Single();
return ioDto;
}
private int? FindInternalOrgid(int? departmentId)
{
if (!departmentId.HasValue)
return (int?) null;
var details = _context.Departments
.Where(x => x.DepartmentId == departmentId.Value)
.Select(x => new
{
x.InternalOrgId,
x.ParentDepartmentId
}).Single();
if (details.InternalOrgId.HasValue)
return details.InternalOrgId;
return findInternalOrgId(details.parentDepartmentId);
}
這里的關鍵考慮因素是避免回傳物體或物體集的存盤庫方法,尤其是在您不需要有關物體的所有資訊的情況下。通過利用IQueryableEF 通過 Linq 提供的 ,我們可以投影到我們需要的資料而不是回傳每個欄位。資料庫服務器可以通過索引更好地適應這種情況,并幫助避免諸如鎖之類的事情。如果您使用的庫執行較低水平域規則或啟用單元測驗,則庫可以公開IQueryable<TEntity>,而不是IEnumerable<TEntity>甚至TEntity使投影和其他EF Linq的善良。
另一種選擇來考慮我在哪里擁有關系很重要的層次結構資料,并且我想快速找到父級的所有相關物體,或者到達特定級別,一個選擇是存盤帶有每條記錄的面包屑,如果該專案會更新曾經被感動。好處是這些型別的檢查變得非常簡單,風險在于可以修改資料關系的任何地方/任何東西都可能使面包屑路徑處于無效狀態。
例如,如果我有一個部門 ID 22,它屬于部門 8,而部門 2 屬于頂級部門,那么 22 的面包屑路徑將是:“2,8”。如果面包屑是空的,我們就有了一個頂級物體。(并且沒有父 ID)我們可以使用一個簡單的string.Split()操作來決議面包屑。這完全避免了對 DB 的遞回訪問。盡管您可能希望在后臺運行維護作業以定期檢查最近修改過的資料,以確保其面包屑路徑準確無誤,并在有任何損壞時提醒您。(通過錯誤代碼或其他方式)
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/380058.html
