2

I'm trying to find a way to refresh my EF entities after they've been modified by another context. Everything works fine, except for navigation properties, which are not updated.

After the change I've tried both:

var objectContext = ((IObjectContextAdapter)context).ObjectContext;
objectContext.Refresh(RefreshMode.ClientWins, entity);

And:

context.Entry(entity).Reload();

But neither cause the relationship to update. This is the code-first model (with some stuff cut out):

public class ElementType : IElementType
{
    [Key]
    public Guid ID { get; set; } = Guid.NewGuid();

    public virtual List<Element> Elements { get; set; }
}

public class ElementType : IElementType
{
    [Key]
    public Guid ID { get; set; } = Guid.NewGuid();

    public virtual ElementType ElementType { get; set; }
}

I'm adding a new Element, and refresh is not updating the Elements relationship property in ElementType. I know things are getting updated by the other context fine, because when I close everything down and restart it, everthing looks like I expect.

The context is still connected, as I can get the new entity from the DB context. I can even force the ElementType to update it's Element collection in the debugger by navagating to the new Element, checking it's relationship property, (which then triggers ElementType to update):

So it's 0 after the update methods above: enter image description here

If I navigate to the context in the debugger, check the Elements set, the new Element is present, and the relationship property is set right (and refers to the same Proxy ElementType object). So this is the DBContext's Elements collection:

enter image description here

And now back to the origional Element:

enter image description here

Everything is up to date!

So I'm pretty sure everything is working except the Refresh/Update method. This question here suggests that Reload should work for lazy loaded relationships, and I can't seem to find any further information on how to actually refresh this collection. Anyone know why it's not working as I'd expect it?

Community
  • 1
  • 1
Joe
  • 6,773
  • 2
  • 47
  • 81
  • 1
    Did you tried `context.Entry(entity).Collections(p => p.YourProperty).Reload();`? – Cristian Szpisjak Mar 30 '17 at 15:11
  • I have not, I could certainly reflect out the navigation properties and update them that way (I want to be able to do it in a generic way), I'll give it a go. – Joe Mar 30 '17 at 15:31

1 Answers1

1

Thanks to Cristian Szpisjak pointing me in the direction of the Collection method for the DbEntityEntry.

I wrote a generic method for refreshing my collections:

    public void Refresh(object entity)
    {
        DbEntityEntry entry = context.Entry(entity);
        entry.Reload();

        var values = entity.GetType().BaseType
                           .GetProperties()
                           .Where(propertyInfo => propertyInfo.GetCustomAttributes(typeof(ReloadCollectionOnRefresh), false).Count() > 0)
                           .Select(propertyInfo => propertyInfo.Name);

        foreach (string value in values)
        {
            var collection = entry.Collection(value);
            collection?.Load();
        }
    }

Where the collection properties are tagged with a ReloadCollectionOnRefresh Custom Attribute:

    [ReloadCollectionOnRefresh]
    public virtual List<MyEntity> MyEntities{ get; set; }

which is just a pretty much empty attribute to 'tag' the collection:

[AttributeUsage(AttributeTargets.Property)]
class ReloadCollectionOnRefresh : Attribute
{
    // can we add checking that this is applied to a virtual collection?
}
Joe
  • 6,773
  • 2
  • 47
  • 81