3

私は(劇的に単純化された)次のような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; }

つまり、ルームには複数のセッションを含めることができます。各セッションには複数のホワイトボードを含めることができます。また、各 Whiteboard には複数の WhiteboardShapes を含めることができます。これらの形状は、それ自体が複数の PolylinePoint を含むことができる WhiteboardShapePolyline など、さまざまなタイプにすることができます。

リモート ユーザーが最初にルームに接続するとき、オブジェクト グラフ全体をそのユーザーに渡す必要があり、そのグラフをデータベースからメモリにできるだけ効率的にロードする方法を見つけようとしています。

もちろん、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 が内部的にその階層を構築する方法のあいまいで目に見えない副作用に依存して、オブジェクト階層全体を本当に望んでいません。

他の提案はありますか?

4

2 に答える 2

3

これにはおそらくプロジェクションを使用します。エンティティ型を返す代わりに、軽量のデータ転送オブジェクトまたは匿名型に射影します。射影すると (たとえば、LINQ クエリを使用して)、読み込みが自動的に行われます。この場合、Include を指定する必要はありません。

于 2009-07-22T13:20:07.697 に答える
0

私はあなたと同様の問題 (より簡単なナビゲーション パス) を抱えていましたが、Designer.cs ファイルの PropertyName が私が期待したものではないことに気付きました。Designer ファイルの PropertyName に変更すると、すべて正常に機能しました。また、2 つの異なるパスを実行したことにも注意してください。

.Include("UnexpectedNameA").Include("UnexpectedNameB")
于 2012-07-19T22:19:53.900 に答える