简体   繁体   English

当它们相互交叉引用时,如何在实体框架中加载嵌套实体?

[英]How do I load nested entities in entity framework when they cross reference each other?

This one is a bit complicated so I've created a sample project (instructions in the readme)这个有点复杂,所以我创建了一个示例项目(自述文件中的说明)

https://github.com/dominicshaw/EntityFrameworkNestingQuirk https://github.com/dominicshaw/EntityFrameworkNestingQuirk

I have the following code:我有以下代码:

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);
}

The data is never written to and staff id 3 has two managers, both set at the point of the first logged line.数据永远不会被写入,并且员工 id 3 有两个经理,都设置在第一个记录行的位置。

I then grab the appraisal for this staff member from the database - the query ef generates looks good and brings back both managers, however in running that query, I lose the manager id (which should be 1) on the staff object (3).然后我从数据库中获取该员工的评估 - 查询 ef 生成看起来不错并带回两个经理,但是在运行该查询时,我丢失了员工 object (3) 的经理 ID(应该是 1)。

When the second log is hit, the managerid is null.命中第二条日志时,managerid 为 null。

I note that the EF model has loaded the secondary manager of the manager even though I didn't ask it to (unless my ef query syntax is wrong?).我注意到 EF model 已加载管理器的辅助管理器,即使我没有要求它(除非我的 ef 查询语法错误?)。 The manager (1) is manager of both 2 and 3, so this is correct, but it should have been loaded into Appraisal->Staff->Manager, not Appraisal->Staff->SecondaryManager->Manager经理 (1) 是 2 和 3 的经理,所以这是正确的,但它应该已经加载到 Appraisal->Staff->Manager,而不是 Appraisal->Staff->SecondaryManager->Manager

Any ideas how I can resolve this?有什么想法可以解决这个问题吗?

The issue is that EF Core thinks that the Manager and SecondaryManager self-referencing relationships are one-to-one relationships, which further means it thinks it can only assign a given entity to a single navigational property.问题在于 EF Core 认为ManagerSecondaryManager自引用关系是一对一的关系,这进一步意味着它认为它只能将给定实体分配给单个导航属性。

The following OnModelCreating() configuration solved the issue for me locally.以下OnModelCreating()配置在本地为我解决了这个问题。 Only the commented lines are changed compared to the configuration you provided:与您提供的配置相比,仅更改了注释行:

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);

Why is the nested Manager populated?为什么要填充嵌套的Manager

The reason for this is the 'relationship fix-up' behavior of EF Core, which means if you load an entity that is referenced by a navigation property, it automatically assigns that entity to the given navigation property.原因是 EF Core 的“关系修复”行为,这意味着如果您加载导航属性引用的实体,它会自动将该实体分配给给定的导航属性。

Even if you run two completely separate queries, if there is a relational connection between the separately loaded entities, EF Core will connect them together in memory.即使您运行两个完全独立的查询,如果单独加载的实体之间存在关系连接,EF Core 也会在 memory 中将它们连接在一起。

In this example, both the main Manager and the nested Manager references the same Staff entity with Id 1, so it would 'fix up' both in memory.在此示例中,主 Manager 和嵌套 Manager 都引用了 ID 为 1 的相同 Staff 实体,因此它将在 memory 中“修复”两者。 But, it happens to 'fix up' the nested one first, and given the one-to-one constraint I suppose it simply stops there.但是,它碰巧首先“修复”了嵌套的一个,并且考虑到一对一的约束,我想它只是停在那里。 Perhaps someone with a deeper understanding of the inner workings of EF Core will enlighten us with more details.也许对 EF Core 内部工作原理有更深入了解的人会用更多细节来启发我们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在Entity Framework中热切加载嵌套实体? - How to eagerly load nested entities in Entity Framework? 实体框架:如何删除相互引用的表行? - Entity Framework: How do I delete table rows that reference each other? 如何使用AutoMapper更新具有嵌套实体的实体,并使用实体框架保存更新的实体? - How do I update an entity with nested entities with AutoMapper and save the updated Entity with Entity Framework? 如何在不延迟加载Entity Framework的情况下加载嵌套实体? - How to load nested entities without lazy loading in Entity Framework? 如何使用实体框架从数据库视图加载相关实体? - How do I load related entities from a database view using entity framework? 如何在实体框架中将一个实体映射到许多实体? - How do I map one entity to many entities in Entity Framework? 如何在实体框架 6 中动态加载子实体 - How can I load Child entities dynamically in Entity Framework 6 使用实体框架,如何在两个模型上添加外键以相互引用 - Using Entity Framework, how can I add a foreign key on two models to reference each other 如何使用Entity Framework Core加载相关实体 - How to load related entities with the Entity Framework Core 如何使用IdentityUser和Entity Framework加载链接的实体 - How to load linked entities with IdentityUser and Entity Framework
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM