1

As I discovered in my question Eagerly Load Navigation Property that is List<OfSomeBaseClass>, it's not possible to load properties of a derived class using the EF .Include() method (this has been suggested as a future EF feature).

I worked around this by iterating my collections that contain a mix of sibling types, individually calling

ctx.Entry(myDerivedType).Reference("PropOfDerivedType").Load();

This results in many extra round trips to the database, but at least it works.

Now I have a need to load such an object hierarchy and save it in the Session of an MVC web application. Since the DbContext should not be part of the session, I believe I must load the object graph AsNoTracking(), like this:

var myGraph = (from my in ctx.MyHierarchyRoot.Include("NonDerivedStuff")
               .AsNoTracking()
               where CONDITION select my).Single();

Question 1

Is it necessary and correct to use .AsNoTracking() if the object graph is to be stored in Session?

I then go on to iterate through the derived siblings in the hierarchy and attempt to load them like this:

foreach (SomeBase b in myGraph.SomeCollection)
{
    if (b is SomeConcreteDerivedType)
    {
        ctx.Entry(b).Reference("SomePropertyOfSomeConcreteDerivedType").Load();
    }
}

However, since I loaded myGraph using .AsNoTracking(), I get:

Member 'Load' cannot be called for property 'SomePropertyOfSomeConcreteDerivedType' because the entity of type 'SomeConcreteDerivedType' does not exist in the context. To add an entity to the context call the Add or Attach method of DbSet.

Question 2

Assuming the answer to Question 1 is "yes", how can I correctly load the navigation properties of derived types?

Community
  • 1
  • 1
Eric J.
  • 147,927
  • 63
  • 340
  • 553

1 Answers1

2

Is it necessary and correct to use .AsNoTracking() if the object graph is to be stored in Session?

It is necessary to make sure that entity stored in session doesn't hold any reference to context (and doesn't need context). This should be performed by detaching entity prior to saving it to session but detaching always breaks relations. The simplest workaround in this case can be disabling proxy creation (lazy loading and dynamic change tracking will not work).

Alternative approach is loading entity graph in normal way and creating deep clone (serialization) of the graph. Deep clone is always fully detached from the context and can be safely stored in the session.

Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • 1
    This seems rather clumsy for a "persistence ignorant" solution. Do you know if the EF team has plans to make improvements in this area? – Eric J. May 24 '12 at 16:23
  • How can I load my derived entities if I disable proxy creation? I *require* lazy loading to load the collection that contains a number of derived types, each with different properties that in turn must be loaded. I can still serialize the object graph, but I would prefer to use the least-heavy hammer that will get the job done. BTW I appreciate all of the work you're doing in SO to help with EF issues. – Eric J. May 24 '12 at 17:18
  • Turns out I cannot deep clone the entity graph at all without disabling proxies, because the proxy types are not known types see e.g. http://stackoverflow.com/questions/7276507/serializable-classes-and-dynamic-proxies-in-ef-how – Eric J. May 24 '12 at 17:30
  • I thought you are using explicit loading (you call `Load` manually). I don't know if there are any improvements planned but I would like to see them as well. Detaching object graphs is clumsy. Serializing dynamic proxies requires some modifications in serialization process - .NET should support this directly with `DataContractSerializer` and `ProxyDataContractResolver` classes. – Ladislav Mrnka May 24 '12 at 19:55
  • I incorrectly thought for a moment that one must create proxies to load after the fact. Loading with proxy creation disabled seems to be working fine (though there are still many DB round-trips). – Eric J. May 24 '12 at 23:24