Y compris les propriétés de navigation des classes TPH Entity Framework

entity-framework inheritance navigation-properties

Question

J'ai une hiérarchie EF qui (considérablement simplifiée) ressemble à ceci:

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

En d'autres termes, une salle peut contenir plusieurs sessions. chaque session peut contenir plusieurs tableaux blancs; et chaque tableau blanc peut contenir plusieurs WhiteboardShapes. Ces formes peuvent être de différents types, notamment WhiteboardShapePolyline, qui peut contenir plusieurs PolylinePoints.

Lorsqu'un utilisateur distant se connecte initialement à la salle, je dois lui transmettre le graphe d'objet entier et j'essaie de comprendre comment charger ce graphe de la base de données en mémoire le plus efficacement possible.

Maintenant, bien sûr, le EF vous permet de charger rapidement, comme ceci:

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

Mais Include () ne me permet pas de charger les PolylinePoints. Plus précisément, si j'essaye:

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

Je reçois l'exception "Un chemin d'inclusion spécifié n'est pas valide. L'EntityType 'SlideLinc.Model.WhiteboardShape' ne déclare pas une propriété de navigation portant le nom" PolylinePoint "."

Cela ne fonctionne pas non plus:

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

Ceci non plus:

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

Ni aucun autre moyen de cadrer le chemin de navigation que je peux penser.

La façon dont j'ai fini par le faire me semble être un bidouillage:

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

Cela fonctionne, mais c'est beaucoup plus de code que je ne le souhaite et beaucoup plus d'accès à la base de données que je ne le souhaite.

La réponse la plus proche que j'ai trouvée est ici , mais mon pauvre cerveau affamé de Linq ne peut pas comprendre comment traduire l'exemple de code dans la hiérarchie plus compliquée que j'ai; De plus, l'exemple de code sur ce lien est sacrément laid et difficile à comprendre. Je ne veux pas vraiment que toute ma hiérarchie d'objets dépende d'un effet secondaire obscur et invisible de la manière dont l'EF construit ses hiérarchies en interne.

D'autres suggestions?

Réponse acceptée

J'utiliserais probablement la projection pour cela. Au lieu de renvoyer des types d'entité, projetez sur des objets de transfert de données légers ou des types anonymes. Lorsque vous projetez (par exemple, avec une requête LINQ), le chargement se fait automatiquement. Vous n'avez pas besoin de spécifier une inclusion dans ce cas.


Réponse populaire

J'avais juste un problème similaire au vôtre (chemin de navigation plus facile) et j'ai réalisé que le PropertyName dans le fichier Designer.cs n'était pas ce à quoi je m'attendais. Une fois que je l'ai changé en PropertyName dans le fichier Designer, tout a bien fonctionné. Notez également que j'ai créé deux chemins différents:

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


Related

Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow