Reputation: 12438
I have this class:
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; }
}
And then I have these 2 repository methods:
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();
}
}
If you look at the LINQ statements for these 2 methods, they are the same just different variable name in the where clause but they have the same value that is being searched for the Id.
What's happening right now is in the first method (GetById), after the LINQ query, the Children is null the reason I have a GetChildren call inside it.
But in the second method (Update), after the LINQ query, the returned object has all its Children. They are the same query and I've checked over and over again to make sure they have the same values and they do.
I don't have any special prior code before the call to these 2; they are just called normally. So I'm really confused by this behavior. What could be causing this?
Upvotes: 5
Views: 13635
Reputation: 17
My guess is that Automapper is the cause in this case. I've recently seen very similar issue where Automapper caused related entities to be loaded.
Upvotes: -2
Reputation: 3355
You probably call the update method after the get method. If EF has already loaded child elements into the entity, they will be present in all subsequent loads of the entity. The essence is the same, the same object!
If you want the navigation property objects to always be loaded, you can specify: builder.Navigation(x => x.Children).AutoInclude() in the entity's fluent configuration, which is set in the OnModelCreating method in your DbContext class;
Upvotes: 4
Reputation: 239400
First, EF Core never automatically includes related entities. EF Core does not support lazy-loading, so all related entities must either be eagerly loaded (via Include
) or explicitly loaded (Load
).
That said, the DbContext in EF maintains an object graph, and as objects are queried, they are persisted in that graph. Once the children were loaded once, EF can re-establish that those related entities again from the graph, without having to query the DB, which is likely what you're seeing here. However, this is not something you should rely on, as it's very much hit or miss. You essentially just got lucky that methods were called in a certain order where this worked. It's always best to assume things won't be there and act accordingly. If EF doesn't need to actually issue a query to make it happen, great, but it should be empowered to if necessary.
Upvotes: 4