我正在创建一个 ASP.NET Core Web API,但在查询上下文时遇到了问题。
Web API 连接到包含 3 个表的数据库:员工、事件和事件责任。一个员工可以创建多个事件。此外,许多员工可以在每个事件中分配许多事件的责任(因此链接事件责任表)。
员工表
+----+-----------------+
| Id | Name |
+----+-----------------+
| 1 | First Employee |
| 2 | Second Employee |
+----+-----------------+
事件表
+----+------------+---------------+
| Id | Creator_Id | Event_Name |
+----+------------+---------------+
| 1 | 1 | Random Event |
| 2 | 1 | Another Event |
+----+------------+---------------+
事件责任表
+----+-------------+----------+
| Id | Employee_Id | Event_Id |
+----+-------------+----------+
| 1 | 1 | 1 |
+----+-------------+----------+
这些模型包括...
事件模型
一个事件只能有一名员工作为创建者。 一个事件也可以有许多员工承担不同的职责。
public int Id { get; set; }
public int? CreatorId { get; set; }
public string EventName { get; set; }
public Employee Creator { get; set; }
public ICollection<EventResponsibilities> EventResponsibilities { get; set; }
员工模型
一个员工可以是许多事件的创建者。 一名员工可以在许多事件中承担责任。
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Event> Event { get; set; }
public ICollection<EventResponsibilities> EventResponsibilities { get; set; }
事件_职责模型
多对多链接表模型。
public int Id { get; set; }
public int? EmployeeId { get; set; }
public int? EventId { get; set; }
public Employee Employee { get; set; }
public Event Event { get; set; }
我在 Controller 方法中运行了以下 LINQ 查询...
return _context.Event.Include(e => e.EventResponsibilities).ThenInclude(e => e.Employee);
我期望得到一个 JSON,其中包含事件的详细信息、其对应的事件职责以及该职责的关联员工。
我实际得到的是下面的json...
[
{
"Id": 1,
"CreatorId": 1,
"EventName": "Random Event",
"Creator": {
"Id": 1,
"Name": "First Employee",
"Event": [],
"EventResponsibilities": [
{
"Id": 1,
"EmployeeId": 1,
"EventId": 1
}
]
},
"EventResponsibilities": [
{
"Id": 1,
"EmployeeId": 1,
"EventId": 1,
"Employee": {
"Id": 1,
"Name": "First Employee",
"Event": [],
"EventResponsibilities": []
}
}
]
},
{
"Id": 2,
"CreatorId": 1,
"EventName": "Another Event",
"Creator": {
"Id": 1,
"Name": "First Employee",
"Event": [
{
"Id": 1,
"CreatorId": 1,
"EventName": "Random Event",
"EventResponsibilities": [
{
"Id": 1,
"EmployeeId": 1,
"EventId": 1
}
]
}
],
"EventResponsibilities": [
{
"Id": 1,
"EmployeeId": 1,
"EventId": 1,
"Event": {
"Id": 1,
"CreatorId": 1,
"EventName": "Random Event",
"EventResponsibilities": []
}
}
]
},
"EventResponsibilities": []
}
]
这不是我想要或期望的... 正如您所看到的,出于某种原因,事件模型的 Creator 导航属性正在显示,即使我在查询中没有请求它,因为我没有为它使用 Include()。
此外,如果您查看 JSON 中返回的第二个事件(“Id”:2),即使没有 EventResponsibilities,也会返回两个创建者行。我不认为这是一个延迟加载问题,因为导航属性不是虚拟的。
我原以为 Creator 对象为 null 或空,因为我没有包含它。
所以我的问题是:为什么即使我没有加载/包含 Creator 导航属性也会包含它?另外,我也想知道如何 不是 包含相关的 Creator 数据并仅在 JSON 中显示 Event Responsibilities 数据。
最佳答案
如果您查看 documentation , 有这个特定的注释实际上是你掉进的陷阱:
Entity Framework Core will automatically fix-up navigation properties to any other entities that were previously loaded into the context instance. So even if you don't explicitly include the data for a navigation property, the property may still be populated if some or all of the related entities were previously loaded.
通过做
.ThenInclude(e => e.Employee);
您请求 EF 获取此 Employee
从而导致它在任何被引用的地方被预先加载。因为在这种特定情况下,您的 Event.Creator
与您明确请求的 EventResponsibilities.Employee
相同,所以在它被提取到 EventResponsibilities
之后,它也会被提取进入您的事件
。
如果您的 Event.Creator
是不同于 EeventsResponsibilities.Employee
的Employee
,您就不会遇到这种异常情况。
这种意外行为和冗余数据是人们使用单独的 DTO 从 Controller 返回数据以确保 API 返回所需数据量恰到好处的原因之一。
作为快速解决方法,您可以简单地在 Creator
属性上添加 JsonIgnoreAttribute
:
[JsonIgnore]
public Employee Creator { get; set; }
但我个人认为将 DTO 和 Entity 混合在同一个类中不是一个好主意,因为这会在任何实体发生变化时引起各种麻烦。
关于c# - 为什么 Entity Framework Core 急于加载不包含的相关实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54107746/