[英]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 认为
Manager
和SecondaryManager
自引用关系是一对一的关系,这进一步意味着它认为它只能将给定实体分配给单个导航属性。
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);
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.