我有這堂課:
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之前,我沒有任何特殊的先前代碼;他們只是正常召喚。所以我對這種行為感到很困惑。可能是什麼導致了這個?
首先,EF Core 永遠不會自動包含相關實體。 EF Core不支持延遲加載,因此所有相關實體必須急切加載(通過Include
)或顯式加載( Load
)。
也就是說,EF中的DbContext維護一個對像圖,並且在查詢對象時,它們會保留在該圖中。一旦孩子們被加載一次 ,EF就可以再次從圖中重新建立那些相關實體,而不必查詢數據庫,這可能就是你在這裡看到的。然而,這不是你應該依賴的東西,因為它非常受歡迎。你基本上很幸運,方法是按照某種順序調用的。最好假設事情不會存在並採取相應行動。如果EF不需要實際發出查詢來實現它,那很好,但是如果有必要的話應該賦予它權力。