Entity Framework POCO - Refresh a navigation property
Asked Answered
F

1

5

I am having some trouble with refreshing the related collection of entities.

Essentially the problem is as follows:

public class Student
{
    public virtual ICollection<Lecture> Lectures { get; set; }

    public void AddLecture(Lecture lecture)
    {
        Lectures.Add(lecture);
    }

    public void CancelChanges()
    {
        _context.Refresh(RefreshMode.StoreWins, this);
        _context.LoadProperty(this, (o) => o.Lectures, 
            MergeOption.OverwriteChanges);
    }
}

public class Grade
{
    public virtual Student { get; set; }
}

Now I have some GUI for adding lectures and, if we want we can cancel the editing process:

public void ExampleEdit()
{
    Student student = _context.Students.SingleOrDefault(/* blah */);
    student.AddLecture(_context.Lectures.SingleOrDefault(/* e.g. math */));
    student.CancelChanges();
    // At this point student SHOULD have no lectures anymore since the 
    // property was loaded with overwrite changes option.
    // Yet the Lectures still contains the lecture we added there
}

So, is the code bad? Is there any method I use incorrectly? Is it possible to COMPLETELY reload the whole object?..

Flatiron answered 1/10, 2010 at 12:36 Comment(0)
M
7

I think you misunderstood MergeOption.OverwriteChanges. By default, anytime the ObjectContext performs a query, if any of the returned objects already exist in the cache the newly returned copies of those objects are ignored.

Please note that it all happens based on the EntityKeys. Basically the EntityKeys of the objects returned from a query are checked, and if an object with the same EntityKey (in the same EntitySet, in your case, Lectures) already exists in the cache, the existing object is left untouched.

However, if you enable OverwriteChanges, then it will Replace the current values of existing entities with values coming from the database, even if the in-memory entity has been edited.

As you can see you are adding a Lecture to the student that is totally new to Student and it will not be overwritten since its EntityKey is different than the ones that coming from database as per your LoadProperty() call.

One solution would be to just simply clear all the Lectures from your student object just before LoadProperty():

public void CancelChanges() {
    _context.Refresh(RefreshMode.StoreWins, this);
    this.Lectures.Clear();
    _context.LoadProperty(this, (o) => o.Lectures, MergeOption.OverwriteChanges);
}
Mordant answered 1/10, 2010 at 20:2 Comment(1)
Thanks a lot for the explanation - it has made a lot of things a lot clearer in my head. And the solution you proposed is very handy - I just updated my code and the thing actually works.Flatiron

© 2022 - 2024 — McMap. All rights reserved.