views:

136

answers:

2

I am attempting to perform the LoadProperty operation from my context to load a navigation property of a navigation property.

My setup is that I have an EntityA, which contains a list of EntityB's, and each EntityB contains a list of EntityC's. I am doing the following programatically:

public virtual List<T> LoadProperty(List<T> entities, string property)
{
    using (MyContext context = new MyContext())
        foreach (T entity in entities)
        {
            context.AttachTo(typeof(T).Name, entity);
            context.LoadProperty(entity, property);
        }

    return entities;
}

I call it as such:

LoadProperty(entityA, "EntityB.EntityC");

I know that the NavigationProperty path is correct, however, this is not working. Is there a way to get this to load?

Edit: Working example using Includes:

using (MyContext context = new MyContext())
{
    var query = from entityA in context.EntityA.Include("EntityB").Include("EntityB.EntityC")
                where entityA.Id == id
                select entityA;

    return query.ToList();
}
+1  A: 

"I know that the NavigationProperty path is correct..." No it's not. Not with a list, it isn't. Try it with the regular Include and you'll see the same result. You can't do this with 1:* properties.

I can't imagine this is the most efficient solution to your problem, but you haven't actually shown why you think you need this.

Craig Stuntz
I tested it with the Include and it worked. See edited ticket. Also there is a need for this when passing an instance of my EntityA around. The initial screen may not need a certain navigation property, but a subsequent screen may. Instead of re-loading the entity using the Includes, I would like to be able to just call LoadProperty to load the property I need. The LoadProperty method works for loading the property "EntityB", but not "EntityB.EntityC".
Brandon
If `Include()` works, it will be more efficient than explicit loading. But projecting onto a view model will be more efficient than either one.
Craig Stuntz
Reviewing the documentation for `LoadProperty`, I can't see any indication that it's intended to support a dotted path.
Craig Stuntz
+1  A: 

First off, your method call context.AttachTo(typeof(T).Name, entity) is not correct and you'll get an InvalidOperationException. ObjectContext.AttachTo Method shows:

public void AttachTo(string entitySetName, Object entity)

So we need to pass the EntitySet name and not the Entity name itself. But the good news is we can get the EntitySet name from MetadataWorkspace by having the Entity name. The code below shows how.

Now if you have 3 levels of object composition and EntityB and EntityC are navigation properties of type EntityCollections, then I don’t think you could load them both with one call to LoadProperty, but you can do it by call LoadProperty twice, here is how it can be done:

using System.Data.Metadata.Edm;

public virtual List<T> LoadProperty(List<T> entities, string property) {
    using (TrialsContext context = new TrialsContext()) {

        EntityContainer container = context.MetadataWorkspace
                                           .GetEntityContainer(context.DefaultContainerName,
                                                               DataSpace.CSpace);
        EntitySetBase entitySet = container.BaseEntitySets
                                           .Where(item => 
                                                  item.ElementType.Name.Equals(typeof(T).Name))
                                           .FirstOrDefault();

        foreach (T entity in entities) {
            context.AttachTo(entitySet.Name, entity);
            context.LoadProperty(entity, property);
        }

    return entities;
}

And you will call it:


// To load EntityA Nav property:
LoadProperty(entityB, "EntityA");

// To Load EntityC Nav property: 
//Let's assume the nav property name for EntityC on EntityB is EntityCList
LoadProperty(entityB, "EntityCList");

This way you will have the full object graph constructed.

Morteza Manavi