Tengo esta clase
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; }
}
Y luego tengo estos 2 métodos de repositorio:
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();
}
}
Si observa las declaraciones LINQ para estos 2 métodos, son el mismo nombre de variable diferente en la cláusula where, pero tienen el mismo valor en el que se está buscando el Id.
Lo que está sucediendo ahora mismo está en el primer método (GetById), después de la consulta LINQ, los hijos son nulos, la razón por la que tengo una llamada GetChildren en su interior.
Pero en el segundo método (Actualización), después de la consulta LINQ, el objeto devuelto tiene todos sus hijos. Son la misma consulta y he comprobado una y otra vez para asegurarse de que tengan los mismos valores y de que sí.
No tengo ningún código anterior especial antes de la llamada a estos 2; simplemente se llaman normalmente. Así que estoy realmente confundido por este comportamiento. ¿Qué podría estar causando esto?
Primero, EF Core nunca incluye automáticamente entidades relacionadas. EF Core no admite la carga diferida, por lo que todas las entidades relacionadas deben cargarse con entusiasmo (a través de Include
) o cargarse explícitamente ( Load
).
Dicho esto, el DbContext en EF mantiene un gráfico de objetos y, a medida que se consultan los objetos, se conservan en ese gráfico. Una vez que los niños se cargaron una vez , EF puede restablecer que esas entidades relacionadas vuelvan a aparecer en el gráfico, sin tener que consultar la base de datos, que es probablemente lo que está viendo aquí. Sin embargo, esto no es algo en lo que debas confiar, ya que es muy impredecible. Básicamente, tuvo suerte de que los métodos se llamaran en un cierto orden en el que funcionaba. Siempre es mejor asumir que las cosas no estarán allí y actuar en consecuencia. Si EF no necesita emitir una consulta para que esto ocurra, genial, pero debe habilitarse si es necesario.