包括Entity Framework TPH类的导航属性

时间:2009-07-21 23:34:57

标签: entity-framework inheritance navigation-properties

我有一个EF层次结构(显着简化)看起来像这样:

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; }

换句话说,一个房间可以包含多个会话;每个Session可以包含多个Whiteboards;每个白板可以包含多个WhiteboardShapes。这些形状可以是各种类型,包括WhiteboardShapePolyline,它本身可以包含多个PolylinePoints。

当远程用户最初连接到房间时,我需要将整个对象图传递给该用户,并且我试图找出如何尽可能有效地将该图从数据库加载到内存中。

现在,当然,EF允许您进行急切加载,如下所示:

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

但Include()不允许我加载PolylinePoints。具体来说,如果我尝试:

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

我得到异常“指定的包含路径无效.EntityType'SlideLinc.Model.WhiteboardShape'不会声明名为'PolylinePoint'的导航属性。”

这也不起作用:

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

这也不是:

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

也没有任何其他方法来构建我能想到的导航路径。

我最终做到这一点的方式确定似乎就像是对我的黑客攻击:

        // 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(); }
                        }
                    }
                }
            }
        }

它可以工作,但它的代码比我想要的要多得多,并且它比我想要的更多数据库访问。

我找到的最接近的答案是here,但我那可怜的Linq饥饿的大脑无法弄清楚如何将示例代码转换为我所拥有的更复杂的层次结构;此外,该链接的示例代码很难看,难以理解。我真的不希望我的整个对象层次结构取决于EF内部构建其层次结构的模糊和不可见的副作用。

还有其他建议吗?

2 个答案:

答案 0 :(得分:3)

我可能会使用投影。而不是返回实体类型,投影到轻量级数据传输对象或匿名类型。投影时(例如,使用LINQ查询),加载会自动进行。在这种情况下,您无需指定包含。

答案 1 :(得分:0)

我只是遇到了类似的问题(更简单的导航路径),我意识到Designer.cs文件中的PropertyName不是我所期望的。一旦我将它更改为Designer文件中的PropertyName,它一切正常 - 请注意我做了两个不同的路径:

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