[英]How do I load nested entities in entity framework when they cross reference each other?
這個有點復雜,所以我創建了一個示例項目(自述文件中的說明)
https://github.com/dominicshaw/EntityFrameworkNestingQuirk
我有以下代碼:
private async Task<(bool Found, Appraisal Appraisal)> Get(int id)
{
var staff = await _context.Staff.FindAsync(3);
_logger.LogInformation("Got Staff Object : Staff {id} has manager set to {managerId} - running query for appraisal", staff.Id, staff.ManagerId);
var appraisal =
await _context.Appraisals
.Include(ap => ap.Staff).ThenInclude(s => s.Manager)
.Include(ap => ap.Staff).ThenInclude(s => s.SecondaryManager)
.Where(ap => ap.Id == id)
.SingleOrDefaultAsync();
_logger.LogInformation("Appraisal Query Run: Staff {id} has manager set to {managerId} - run completed", staff.Id, staff.ManagerId);
if (appraisal != null)
{
_logger.LogInformation("Appraisal->Staff->2ndManager->Manager={id} (We should NOT have this)", appraisal.Staff.SecondaryManager?.ManagerId);
return (true, appraisal);
}
return (false, null);
}
數據永遠不會被寫入,並且員工 id 3 有兩個經理,都設置在第一個記錄行的位置。
然后我從數據庫中獲取該員工的評估 - 查詢 ef 生成看起來不錯並帶回兩個經理,但是在運行該查詢時,我丟失了員工 object (3) 的經理 ID(應該是 1)。
命中第二條日志時,managerid 為 null。
我注意到 EF model 已加載管理器的輔助管理器,即使我沒有要求它(除非我的 ef 查詢語法錯誤?)。 經理 (1) 是 2 和 3 的經理,所以這是正確的,但它應該已經加載到 Appraisal->Staff->Manager,而不是 Appraisal->Staff->SecondaryManager->Manager
有什么想法可以解決這個問題嗎?
問題在於 EF Core 認為Manager
和SecondaryManager
自引用關系是一對一的關系,這進一步意味着它認為它只能將給定實體分配給單個導航屬性。
以下OnModelCreating()
配置在本地為我解決了這個問題。 與您提供的配置相比,僅更改了注釋行:
builder.Entity<Staff>().HasIndex(e => e.ManagerId).IsUnique(false);
builder.Entity<Staff>()
.HasOne(a => a.Manager)
.WithMany() // Changed
.HasForeignKey(s => s.ManagerId)
.IsRequired(false)
.OnDelete(DeleteBehavior.NoAction);
builder.Entity<Staff>().HasIndex(e => e.SecondaryManagerId).IsUnique(false);
builder.Entity<Staff>()
.HasOne(a => a.SecondaryManager)
.WithMany() // Changed
.HasForeignKey(s => s.SecondaryManagerId)
.IsRequired(false)
.OnDelete(DeleteBehavior.NoAction);
Manager
?原因是 EF Core 的“關系修復”行為,這意味着如果您加載導航屬性引用的實體,它會自動將該實體分配給給定的導航屬性。
即使您運行兩個完全獨立的查詢,如果單獨加載的實體之間存在關系連接,EF Core 也會在 memory 中將它們連接在一起。
在此示例中,主 Manager 和嵌套 Manager 都引用了 ID 為 1 的相同 Staff 實體,因此它將在 memory 中“修復”兩者。 但是,它碰巧首先“修復”了嵌套的一個,並且考慮到一對一的約束,我想它只是停在那里。 也許對 EF Core 內部工作原理有更深入了解的人會用更多細節來啟發我們。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.