2015-04-15 14 views
23

Ho installato Entity Framework e funziona bene la maggior parte del tempo che mi serve. Ho una struttura come questaEntity Framework - Stop Lazy Caricamento di entità correlate su richiesta?

public partial class Topic : Entity 
{ 
    public Guid Id { get; set; } 
    public string Name { get; set; } 
    public DateTime CreateDate { get; set; } 
    public virtual Post LastPost { get; set; } 
    public virtual Category Category { get; set; } 
    public virtual IList<Post> Posts { get; set; } 
    public virtual IList<TopicTag> Tags { get; set; } 
    public virtual MembershipUser User { get; set; } 
    public virtual IList<TopicNotification> TopicNotifications { get; set; } 
    public virtual IList<Favourite> Favourites { get; set; } 
    public virtual Poll Poll { get; set; } 
} 

Come si può vedere, ho un numero di entità correlate che sono elenchi. Questi sono mappati come standard e sono pigri caricata in modo che posso chiamare Topic.Posts o Topic.TopicNotifications ecc ... (Mapping sotto)

HasOptional(t => t.LastPost).WithOptionalDependent().Map(m => m.MapKey("Post_Id")); 
HasOptional(t => t.Poll).WithOptionalDependent().Map(m => m.MapKey("Poll_Id"));    
HasRequired(t => t.Category).WithMany(t => t.Topics).Map(m => m.MapKey("Category_Id")); 
HasRequired(t => t.User).WithMany(t => t.Topics).Map(m => m.MapKey("MembershipUser_Id")); 
HasMany(x => x.Posts).WithRequired(x => x.Topic).Map(x => x.MapKey("Topic_Id")).WillCascadeOnDelete(); 
HasMany(x => x.TopicNotifications).WithRequired(x => x.Topic).Map(x => x.MapKey("Topic_Id")).WillCascadeOnDelete(); 
HasMany(t => t.Tags) 
    .WithMany(t => t.Topics) 
    .Map(m => 
       { 
        m.ToTable("Topic_Tag"); 
        m.MapLeftKey("TopicTag_Id"); 
        m.MapRightKey("Topic_Id"); 
       }); 

Questo è tutto un pozzo. Ma in un paio di occasioni ho la necessità di popolare manualmente Topic.Posts e Topic.Favorites.

Ma se provo e impostare Topic.Posts = SomeCollection innesca il carico pigro e carica tutti i post prima, e poi mi permette di impostare la mia collezione in modo da ottenere due set di SQL eseguito (il primo non voglio)

C'è comunque, per spegnere manualmente il carico pigro su richiesta per quando voglio impostare manualmente la raccolta?

speranza che abbia un senso ...:/

+5

Sto rilevando un problema XY qui http://meta.stackexchange.com/a/66378/134199 - Penso che il tuo vero problema sia questa "necessità di compilare manualmente Topic.Posts e Topic.Favorites". Probabilmente stai provando a fare qualcosa che è molto meglio realizzato in un modo diverso, poiché ciò che stai facendo non ha alcun senso. Che cosa stai cercando di fare esattamente ... e perché? –

+1

Seguirò ciò che @ErikFunkenbusch sta dicendo. Perché è necessario ricreare manualmente le raccolte Posts e Favorites? –

+0

Se rispondi a quello che stai cercando di fare, allora potremmo davvero essere in grado di aiutarti a risolvere il tuo vero problema .. non il problema che pensi di avere perché pensi di dover fare una cosa particolare per risolverti problema. –

risposta

3

Dal momento che si sta utilizzando lazy loading, è necessario disporre di proxy generati per le classi e le proprietà di raccolta.

Sostituire queste proprietà di raccolta proxy con le proprie raccolte mi sembra piuttosto strano. Perderai il rilevamento delle modifiche e molto probabilmente otterrai un paio di altri strani effetti collaterali.

Suggerirei di utilizzare i proxy/il caricamento lazy e rinunciare all'idea di sostituire le raccolte o di non utilizzare i proxy e ottenere il controllo completo sulle classi POCO generate.

Quale di entrambi gli approcci si adatta meglio alle proprie esigenze dipende dall'utilizzo generale del framework di entità.

12

Non sono a conoscenza di un approccio mirato a questo scenario esatto quindi dovrei andare con una disabilitazione/abilitazione temporanea del caricamento lazy.

using(var context = new MyContext()) 
{ 
    context.Configuration.LazyLoadingEnabled = false; 
    // do your thing using .Include() or .Load() 
    context.Configuration.LazyLoadingEnabled = true; 
} 

nota, tuttavia, che si tratta di una configurazione globale quindi ci potrebbe essere un problema di concorrenza, se ciò accade nel vostro scenario.

+1

Discuterei di questo approccio poiché non è più possibile garantire la presenza dell'oggetto incluso negli oggetti entità, quindi è necessario assicurarsi di testare sempre i record null prima di tentare di accedere agli oggetti inclusi. L'attivazione/disattivazione del caricamento e dei proxy pigri durante il runtime può comportare numerose conseguenze impreviste e causare il debug del mal di testa. – AllMadHare

+2

@AllMadHare: sono d'accordo. La tua soluzione è molto meglio. –

+1

@JeroenVannevel Non è una proprietà globale .. almeno non in EF 6. Immagino che ci sia un modo per impostarlo globalmente e che la configurazione è probabilmente clonata dal default/globale, ma Configuration (e quel flag) sono proprietà di istanza . –

21

È preferibile disattivare il caricamento lento per impostazione predefinita e specificare invece quando si desidera caricare i dati aggiuntivi in ​​primo luogo. EF è impostato per consentire il caricamento Eager utilizzando la funzione .Include() sulla tua query, con il caricamento pigro può diventare disordinato se si avvia accendendo/spegnendo per varie funzioni, è meglio semplicemente spegnerlo e gestirlo cosa/quando si desidera caricare i dati se si sente la necessità di spegnerlo.

Vedere https://msdn.microsoft.com/en-nz/data/jj574232.aspx per esempi specifici e una ripartizione dei diversi modi in cui è possibile caricare/scaricare i dati. Il primo esempio mostra come è possibile passare attraverso i post di un blog, che è simile a ciò che si desidera ottenere.

var topics = context.Topics 
         .Include(t => t.Posts) 
         .ToList(); 
8

Non mi consiglia di disattivare il caricamento lazing su una base per richiesta. Come suggerisce AllMadHare, è possibile disattivare completamente il caricamento pigro, ma ciò potrebbe imporre modifiche al modo in cui si caricano tutti i dati.Suggerirei di rimuovere la parola chiave virtuale da messaggi in modo che la classe assomiglia a questo:

public partial class Topic : Entity 
{ 
    public Guid Id { get; set; } 
    public string Name { get; set; } 
    public DateTime CreateDate { get; set; } 
    public virtual Post LastPost { get; set; } 
    public virtual Category Category { get; set; } 
    public IList<Post> Posts { get; set; } 
    public virtual IList<TopicTag> Tags { get; set; } 
    public virtual MembershipUser User { get; set; } 
    public virtual IList<TopicNotification> TopicNotifications { get; set; } 
    public virtual IList<Favourite> Favourites { get; set; } 
    public virtual Poll Poll { get; set; } 
} 

Per la documentazione trovata qui: https://msdn.microsoft.com/en-us/data/jj574232.aspx#lazyOffProperty questo vi permetterà di carico pigri tutte le altre proprietà di navigazione e messaggi di carico ansioso se necessario .

Problemi correlati