【问题标题】:Entity Framework Core automatically recursively including collection for each entity [duplicate]实体框架核心自动递归地包括每个实体的集合[重复]
【发布时间】:2021-12-30 19:32:48
【问题描述】:

我有四个由 Entity Framework Core (2.1.4) 自动生成的模型(使用脚手架),它们之间相互关联。

public partial class Run
{
    public int Id { get; set; }
    public int RunCarId { get; set; }
    public int RunExtraInfoId { get; set; }
    ...
    public RunExtraInfo RunExtraInfo{ get; set; }
    public RunCar RunCar{ get; set; }
    public ICollection<Weighing> Weighings{ get; set; }
}

public partial class RunExtraInfo
{
    public int Id { get; set; }
    ...
    public ICollection<CorridaCt> Runs { get; set; }
}

public partial class RunCar
{
    public int Id { get; set; }
    ...
    public Run Run{ get; set; }
}

public partial class Weighing
{
    public int Id { get; set; }
    public int RunId { get; set; }
    ...
    public Run Run{ get; set; }
}

但每当我在 Run 上包含我需要的所有信息时,所有其他关系都会加载到实体中,这使得它非常递归。

例子:

var runs = ContextSQL.Runs
                     .Include(c => c.RunExtraInfo)
                     .Include(c => c.RunCar)
                     .Include(c => c.Weighings)
                     .ToList();
return runs;

生成:

[
  {
    id: 0,
    ...
    runExtraInfo: {
      id: 0,
      ...
      runs: [
        {
          id: 0,
          runExtraInfo: {id: 0 runs: [...]},
          runCar: {id: 0, runs: [...]}
        }
      ]
    },
    runcar: {
      id: 0,
      runs: [
        {id: 0, runExtraInfo: [...], runs: [...]}
      ]
    }
  }
]

我认为只有当我们用Include() 明确包含它们时,实体才应该包含关系,我错了吗?

我该如何解决这个问题?

【问题讨论】:

  • 一种选择是在要防止递归的地方使用属性[Script Ignore]
  • 简而言之,您无法阻止 EF Core 这样做,因为这是设计使然。如果您有序列化问题,请使用单独的类或序列化选项/属性。

标签: c# linq entity-framework-core


【解决方案1】:

为避免这种情况,您需要使用显式加载,如此处Explicit Loading in Entity Framework core 所述。

或者您只需要返回您需要的字段,而不是数据库模型:

var runs = ContextSQL.Runs
    .Include(c => c.RunExtraInfo)
    .Include(c => c.RunCar)
    .Include(c => c.Weighings)
    .Select(c => new { c.Id, c.RunExtraInfo, c.RunCar, c.Weighings })
    .ToList();
return runs;

或者不使用匿名对象,您可以使用仅包含所需数据的 DTO(删除不需要的字段和循环引用):

var runs = ContextSQL.Runs
    .Include(c => c.RunExtraInfo)
    .Include(c => c.RunCar)
    .Include(c => c.Weighings)
    .Select(c => new RunDTO(c))
    .ToList();
return runs;

请参阅(外部微软链接)Create Data Transfer Objects (DTOs)

正如您问题的 cmets 中所述,您也可以将 [JsonIgnore] 属性用于您不想转换为 Json 的字段,但您可能更喜欢使用 DTO。

【讨论】:

  • 我选择了 DTO 选项,效果很好,谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-24
  • 1970-01-01
  • 2017-11-15
  • 2021-04-03
  • 1970-01-01
  • 2015-12-15
  • 1970-01-01
相关资源
最近更新 更多