什么会自动导致EF Core包含Collection属性?

时间:2017-12-29 05:22:11

标签: c# asp.net-core entity-framework-core ef-core-2.0

我有这堂课:

public class Subject
{
    public int Id { get; set; }

    [Required]
    [StringLength(50)]
    public string Name { get; set; }

    [StringLength(50)]
    public string Code { get; set; }

    public int LevelId { get; set; }
    public int? ParentId { get; set; }
    public int Order { get; set; }

    [ForeignKey("LevelId")]
    public Level Level { get; set; }

    [ForeignKey("ParentId")]
    public Subject Parent { get; set; }

    public ICollection<Subject> Children { get; set; }

    [Column(TypeName = "datetime2")]
    public DateTime? DeletedAt { get; set; }
}

然后我有这两个存储库方法:

public Subject GetById(int subjectId)
{
    var subjectFound = _context.Subjects.Where(subj => subj.Id == subjectId)
        .SingleOrDefault();
    var subject = _mapper.Map<Subject>(subjectFound);
    if (subjectFound != null)
    {
        subject.Children = GetChildren(subject.Id).ToList();
    }
    return subject;
}

public void Update(Subject existingSubject)
{
    var subjectToUpdate = _context.Subjects.Where(subj => subj.Id == existingSubject.Id)
        .SingleOrDefault();
    if (subjectToUpdate != null)
    {
        _mapper.Map(existingSubject, subjectToUpdate);
        _context.Update(subjectToUpdate);

        SaveChildren(subjectToUpdate.Id, existingSubject.LevelId, existingSubject.Children);

        _context.SaveChanges();
    }
}

如果查看这两种方法的LINQ语句,它们在where子句中只是不同的变量名,但它们具有相同的值,正在搜索Id。

现在发生的事情是在第一个方法(GetById)中,在LINQ查询之后,Children为null,因为我在其中有一个GetChildren调用。

但是在第二种方法(Update)中,在LINQ查询之后,返回的对象具有其所有Children。它们是相同的查询,我一遍又一遍地检查,以确保它们具有相同的值,并且确实具有相同的值。

在拨打这两个号码之前,我没有任何特殊的先前代码;它们只是正常调用。所以我对这种行为感到很困惑。可能导致这种情况的原因是什么?

2 个答案:

答案 0 :(得分:2)

首先,EF Core 从不自动包含相关实体。 EF Core不支持延迟加载,因此所有相关实体必须急切加载(通过Include)或显式加载(Load)。

也就是说,EF中的DbContext维护一个对象图,并且在查询对象时,它们会保留在该图中。一旦孩子们一次加载,EF就可以再次从图表中重新建立那些相关实体,而不必查询数据库,这可能是你在这里看到的。然而,这不是你应该依赖的东西,因为它非常受欢迎。你基本上很幸运,方法是按照某种顺序调用的。总是最好假设事情不会在那里并采取相应的行动。如果EF不需要实际发出查询来实现它,那很好,但是如果有必要,它应该被赋予权力。

答案 1 :(得分:0)

您可能在 get 方法之后调用了 update 方法。如果 EF 已经将子元素加载到实体中,它们将出现在实体的所有后续加载中。本质一样,同一个对象!

如果你希望导航属性对象总是被加载,你可以在实体的流畅配置中指定:builder.Navigation(x => x.Children).AutoInclude(),在你的DbContext的OnModelCreating方法中设置班级;