簡體   English   中英

當它們相互交叉引用時,如何在實體框架中加載嵌套實體?

[英]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 認為ManagerSecondaryManager自引用關系是一對一的關系,這進一步意味着它認為它只能將給定實體分配給單個導航屬性。

以下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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM