Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/81.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 当嵌套实体相互引用时,如何在实体框架中加载它们?_C#_Sql_Sql Server_Entity Framework_Entity Framework Core - Fatal编程技术网

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

C# 当嵌套实体相互引用时,如何在实体框架中加载它们?,c#,sql,sql-server,entity-framework,entity-framework-core,C#,Sql,Sql Server,Entity Framework,Entity Framework Core,这个有点复杂,所以我创建了一个示例项目(自述文件中的说明) 我有以下代码: private异步任务Get(int-id) { var staff=wait_context.staff.FindAsync(3); _logger.LogInformation(“获取Staff对象:Staff{id}已将manager设置为{managerId}-正在运行评估查询”,Staff.id,Staff.managerId); 风险价值评估= 等待评估 .包括(ap=>ap.Staff)。然后包括(s=>

这个有点复杂,所以我创建了一个示例项目(自述文件中的说明)

我有以下代码:

private异步任务Get(int-id)
{
var staff=wait_context.staff.FindAsync(3);
_logger.LogInformation(“获取Staff对象:Staff{id}已将manager设置为{managerId}-正在运行评估查询”,Staff.id,Staff.managerId);
风险价值评估=
等待评估
.包括(ap=>ap.Staff)。然后包括(s=>s.Manager)
.包括(ap=>ap.Staff)。然后包括(s=>s.Secondary Manager)
.Where(ap=>ap.Id==Id)
.SingleOrDefaultAsync();
_logger.LogInformation(“评估查询运行:Staff{id}已将manager设置为{managerId}-Run completed”,Staff.id,Staff.managerId);
如果(评估!=null)
{
_logger.LogInformation(“evaluation->Staff->2ndManager->Manager={id}(我们不应该有这个)”,evaluation.Staff.SecondaryManager?.ManagerId);
回报(真实,评估);
}
返回(false,null);
}
数据从不写入,员工id 3有两个管理器,都设置在第一条记录行的点上

然后,我从数据库中获取该员工的评估-ef生成的查询看起来不错,并将两个经理都带回来,但是在运行该查询时,我丢失了staff对象(3)上的经理id(应该是1)

当命中第二个日志时,managerid为null

我注意到EF模型已经加载了管理器的辅助管理器,即使我没有要求它加载(除非我的EF查询语法错误?)。经理(1)是2和3的经理,因此这是正确的,但它应该加载到“评估->员工->经理”中,而不是“评估->员工->二级经理->经理”中


有什么办法可以解决这个问题吗?

问题是EF Core认为
管理器
二级管理器
自引用关系是一对一关系,这进一步意味着它认为它只能将给定实体分配给单个导航属性

下面的
OnModelCreating()
配置在本地为我解决了这个问题。与您提供的配置相比,只更改了注释行:

builder.Entity().HasIndex(e=>e.ManagerId).IsUnique(false);
builder.Entity()
.HasOne(a=>a.Manager)
.WithMany()//已更改
.HasForeignKey(s=>s.ManagerId)
.IsRequired(假)
.OnDelete(DeleteBehavior.NoAction);
builder.Entity().HasIndex(e=>e.SecondaryManagerId).IsUnique(false);
builder.Entity()
.HasOne(a=>a.secondary经理)
.WithMany()//已更改
.HasForeignKey(s=>s.SecondaryManagerId)
.IsRequired(假)
.OnDelete(DeleteBehavior.NoAction);
为什么要填充嵌套的
管理器
? 原因是EF Core的“关系修复”行为,这意味着如果加载导航属性引用的实体,它会自动将该实体指定给给定的导航属性

即使运行两个完全独立的查询,如果单独加载的实体之间存在关系连接,EF Core也会在内存中将它们连接在一起


在本例中,主管理器和嵌套管理器都引用Id为1的同一人员实体,因此它将在内存中“修复”这两个实体。但是,它碰巧先“修复”了嵌套的一个,并且考虑到一对一的约束,我想它就到此为止了。也许有人对EF Core的内部工作有更深入的了解,会给我们提供更多的细节。

啊,这太棒了——我已经记下了它正在进行一次修复,但它做了一次错误的修复,但我从来没有想过要将它更新为WithMany,以便让它同时修复它们。非常感谢我将更新我的代码。我在EFCore回购协议上创建了一个问题-不确定这是否是正确的做法,但我认为值得检查。哦,如果你愿意链接它,我很有兴趣关注这个问题。EF Core中的自引用是一个令人头痛的问题。。。或者至少用意想不到的行为让人们惊讶。当然。是的,我明白了!;-)