Navigation properties from Entity Framework TPH classes are included.

entity-framework inheritance navigation-properties

Question

I have an EF hierarchy that, when substantially skewed, looks like this:

class Room { EntityCollection<Session> Sessions; }
class Session { EntityCollection<Whiteboard> Whiteboards; EntityReference Room; }
class Whiteboard { EntityCollection<WhiteboardShape> WhiteboardShapes; EntityReference Session; }
abstract class WhiteboardShape { EntityReference Whiteboard; }
class WhiteboardShapeEllipse : WhiteboardShape { }
class WhiteboardShapePolyline { WhiteboardShape { EntityCollection<PolylinePoint> PolylinePoints }
class PolylinePoint { EntityReference<WhiteboardShapePolyline> WhiteboardShapePolylineReference; }

In other words, a Room may have a number of Sessions, each of which may include a number of Whiteboards, and each of which may include a number of WhiteboardShapes. These forms may include a WhiteboardShapePolyline, which itself can have several PolylinePoints, among other sorts.

I need to provide the whole object graph to a remote user when they first join to the room, thus I'm attempting to figure out how to load that graph from the database into memory as quickly as feasible.

Of course, eager loading is possible with the EF, as seen here:

      Room room = ctx.Room
            .Include("Sessions.Whiteboards")
            .FirstOrDefault(r => r.OwnerID == ownerUserID && r.Name == roomName);

However, Include() prevents me from loading the PolylinePoints. In particular, if I try:

        Room room = ctx.Room
            .Include("Sessions.Whiteboards.WhiteboardShape.PolylinePoint")
            .FirstOrDefault(r => r.OwnerID == ownerUserID && r.Name == roomName);

I recognize the exception "The Include path that was supplied is invalid. A navigation property with the name "PolylinePoint" is not declared for the entity type "SlideLinc.Model.WhiteboardShape"."

Also ineffective is this

.Include("Sessions.Whiteboards.WhiteboardShapePolyline.PolylinePoint")

Further, this:

.Include("Sessions.Whiteboards.WhiteboardShape.WhiteboardShapePolyline.PolylinePoint")

I can't think of any other way to frame the navigational route.

The method I ultimately chose to use seemed seems like a hack to me:

        // Make sure we've got everything loaded.
        if (room != null)
        {
            if (!room.Sessions.IsLoaded) { room.Sessions.Load(); }
            foreach (Session session in room.Sessions)
            {
                if (!session.Whiteboards.IsLoaded) { session.Whiteboards.Load(); }
                foreach (Whiteboard whiteboard in session.Whiteboards)
                {
                    if (!whiteboard.WhiteboardShape.IsLoaded) { whiteboard.WhiteboardShape.Load(); }
                    foreach (WhiteboardShape shape in whiteboard.WhiteboardShape)
                    {
                        if (shape is WhiteboardShapePolyline)
                        {
                            WhiteboardShapePolyline polyline = (WhiteboardShapePolyline)shape;
                            if (!polyline.PolylinePoints.IsLoaded) { polyline.PolylinePoints.Load(); }
                        }
                    }
                }
            }
        }

Although it works, there is a lot more code and database queries than I want.

The closest solution I've come across is here, but my poor Linq-starved brain can't figure out how to convert the example code into the more complex hierarchy that I've got; in addition, the sample code at that link is so dreadfully ugly and challenging to comprehend. I really don't want my whole object hierarchy to be reliant on a mysterious, undetectable byproduct of how the EF internally builds its hierarchies.

Any further recommendations?

1
3
5/23/2017 12:19:32 PM

Accepted Answer

For this, I think I'd utilize projection. Project onto lightweight data transfer objects or anonymous types rather than returning entity types. The loading occurs automatically when you project (for instance, using a LINQ query). In this situation, an Include is not necessary.

3
7/22/2009 1:20:07 PM

Popular Answer

Your issue with the simpler navigation route reminded me that the PropertyName in the Designer.cs file was not what I had anticipated. Everything went well once I changed it to the PropertyName in the Designer file; take notice that I used two separate routes, which became:

.Include("UnexpectedNameA").Include("UnexpectedNameB")


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow