2

I need to find out, whether the owner of a given EntityCollection<T> is detached from the Context or not. The reason is to avoid failing subsequent Load() calls to the collection. However, the _owner and _wrappedOwner field of the collection is not accessible, and none of the available metadata seems to provide this information.

Is there a way to find out the owner (or at least it's EntityState)?

Context: Since we are not allowed, by policy, to use lazy loading, I want to create some easy explicit late loading when needed, preferably using a generic method. This is how I do it currently, asking for the owner as parameter:

public static EntityCollection<T> ReloadIfNeeded<T>(this EntityCollection<T> collection, EntityObject owner) where T : EntityObject {
    if (owner.EntityState != EntityState.Detached && !collection.IsLoaded) {
        collection.Load();
    }
    return collection;
}

Example call:

var orders = customer.Orders.ReloadIfNeeded(customer); //I would like to get rid of the customer parameter here...

I am using .NET Version 4.0.

EDIT: My solution, implementing the answer by Ognyan Dimitrov:

public static EntityCollection<T> ReloadIfNeeded<T>(this EntityCollection<T> collection) where T : EntityObject {
    try {
        if (!collection.IsLoaded) {
            collection.Load();
        }
    } catch (InvalidOperationException) {
        //just leave unloaded
    }
    return collection;
}

This does not consider the entity state, as originally sought after, but gets rid of the unwanted parameter in expense of a try/catch clause.

leppie
  • 115,091
  • 17
  • 196
  • 297
Marcel
  • 15,039
  • 20
  • 92
  • 150
  • Are those fields there but private? If so you can use reflection and get them. – Ognyan Dimitrov Jan 08 '15 at 15:17
  • @OgnyanDimitrov Yes, and I know. But I feel that this will get real slow. – Marcel Jan 08 '15 at 15:24
  • Most of the time the real performance hit is not in CPU time but in IO - disk read/write, db queries, external services, etc. You can try to measure it too. At the end it is about how the end user 'feels/perceives' the program. Are you trying to implement some sort of 2nd level cache for EF? – Ognyan Dimitrov Jan 09 '15 at 08:02
  • @OgnyanDimitrov I am trying to work around our "no lazy loading" policy, by creating some sort of explicit, safe, late loading. See the "context" paragraph. – Marcel Jan 09 '15 at 08:06

1 Answers1

2

Combing the EntityCollection with Reflector and looking at the code I see that this class has a public method

public override void Load(MergeOption mergeOption)
{
    base.CheckOwnerNull();
    this.Load(null, mergeOption);
}

which then calls another internal Load method :

internal void Load(List<IEntityWrapper> collection, MergeOption mergeOption)
{
    bool flag;
    ObjectQuery<TEntity> query = base.ValidateLoad<TEntity>(mergeOption, "EntityCollection", out flag);
    base._suppressEvents = true;
    try
    {
        if (collection == null)
        {
            base.Merge<TEntity>(flag ? RelatedEnd.GetResults<TEntity>(query) : Enumerable.Empty<TEntity>(), mergeOption, true);
        }
        else
        {
            base.Merge<TEntity>(collection, mergeOption, true);
        }
    }
    finally
    {
        base._suppressEvents = false;
    }
    this.OnAssociationChanged(CollectionChangeAction.Refresh, null);
}

It looks like that it checks internally if the owner is there which will save you from 'failing subsequent Load()' if you catch the exception. If you call Load(MergeOption) with MergeOption in any moment you specify.

Does 'Detached' in your case means that the Entity has just came from the front end from a POST request? If you have previous access to the parent entity you can check its state with :

_context.Entry(entity).State

I do not know if detaching the parent Entity will reflect in setting the 'state' of the children to the same state.

Ognyan Dimitrov
  • 6,026
  • 1
  • 48
  • 70
  • "Detached" in my case would mostly mean, that the object just got created in memory, and has not been added to the context, YET. – Marcel Jan 12 '15 at 07:15
  • I now have mostly done as your solution suggest, by adding a try/catch around the relevant code. – Marcel Jan 12 '15 at 07:17