Comprese le proprietà di navigazione dalle classi TPH di Entity Framework

entity-framework inheritance navigation-properties

Domanda

Ho una gerarchia EF che (drasticamente semplificata) assomiglia a qualcosa del genere:

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 altre parole, una stanza può contenere più sessioni; ogni sessione può contenere più lavagne bianche; e ogni lavagna può contenere più WhiteboardShapes. Queste forme possono essere di vari tipi, tra cui una WhiteboardShapePolyline, che a sua volta può contenere più PolylinePoints.

Quando un utente remoto si connette inizialmente alla stanza, ho bisogno di passare l'intero grafico dell'oggetto a quell'utente, e sto cercando di capire come caricare quel grafico dal database in memoria nel modo più efficiente possibile.

Ora, naturalmente, l'EF ti permette di fare il caricamento avido, in questo modo:

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

Ma Include () non mi permette di caricare i PolylinePoints. Specificamente, se provo:

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

Ricevo l'eccezione "Un percorso di inclusione specificato non è valido. EntityType 'SlideLinc.Model.WhiteboardShape' non dichiara una proprietà di navigazione con il nome 'PolylinePoint'."

Né funziona così:

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

Né questo:

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

Né nessun altro modo di inquadrare il percorso di navigazione a cui possa pensare.

Il modo in cui ho finito per farlo sembra sicuramente un trucco per 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(); }
                        }
                    }
                }
            }
        }

Funziona, ma è molto più codice di quello che voglio, ed è un mucchio di accessi al database più numerosi di quanto io voglia.

La risposta più vicina che ho trovato è qui , ma il mio povero cervello affamato di Linq non riesce a capire come tradurre il codice di esempio nella gerarchia più complicata che ho; inoltre, il codice di esempio a quel link è dannatamente brutto e difficile da capire. Non voglio davvero che la mia intera gerarchia di oggetti dipenda da un oscuro e invisibile effetto collaterale di come l'EF costruisce internamente le sue gerarchie.

Qualche altro suggerimento?

Risposta accettata

Probabilmente userò la proiezione per questo. Invece di restituire tipi di entità, proiettate su oggetti di trasferimento dati leggeri o tipi anonimi. Quando progetti (ad es. Con una query LINQ), il caricamento avviene automaticamente. Non è necessario specificare un Includi in questo caso.


Risposta popolare

Stavo solo avendo un problema simile al tuo (percorso di navigazione più semplice) e mi sono reso conto che il PropertyName nel file Designer.cs non era quello che mi aspettavo. Una volta che l'ho modificato in PropertyName nel file di Designer, tutto ha funzionato bene - nota anche che ho fatto due percorsi diversi che sono diventati:

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


Related

Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow