web-dev-qa-db-fra.com

Entity Framework - Stop Lazy Loading Entités liées à la demande?

J'ai Entity Framework installé et cela fonctionne très bien la plupart du temps j'en ai besoin. J'ai une structure comme ça

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

Comme vous pouvez le voir, j'ai un certain nombre d'entités liées qui sont des listes. Ceux-ci sont mappés en standard et sont chargés paresseux afin que je puisse appeler Topic.Posts ou Topic.TopicNotifications etc ... (Mappages ci-dessous)

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

C'est bien. Mais à quelques reprises, j'ai besoin de remplir manuellement Topic.Posts et Topic.Favorites.

Mais si j'essaie de définir Topic.Posts = SomeCollection il déclenche le chargement paresseux et charge tous les messages en premier, puis me permet de définir ma collection pour que j'exécute deux ensembles de sql (le premier que je ne veux pas)

Y a-t-il de toute façon, pour désactiver le chargement paresseux manuellement à la demande juste au moment où je veux définir la collecte manuellement?

J'espère que cela a du sens ...: /

25
leen3o

Il serait préférable de désactiver le chargement paresseux par défaut et de spécifier à la place quand vous souhaitez charger les données supplémentaires en premier lieu. EF est configuré pour autoriser le chargement Désireux en utilisant la fonction .Include () sur votre requête, avec un chargement paresseux, il peut devenir compliqué si vous commencez à l'activer/le désactiver pour diverses fonctions, il vaut mieux l'éteindre et le gérer quoi/quand vous voulez que les données soient chargées si vous ressentez le besoin de les désactiver.

Voir https://msdn.Microsoft.com/en-nz/data/jj574232.aspx pour des exemples spécifiques et une ventilation des différentes façons dont vous pouvez charger des données avec impatience/paresseux. Le premier exemple montre comment vous pouvez extraire des publications d'un blog, ce qui est similaire à ce que vous souhaitez obtenir.

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

Je ne suis pas au courant d'une approche ciblée sur ce scénario exact, je devrais donc opter pour une désactivation/activation temporaire du chargement paresseux.

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

Notez cependant qu'il s'agit d'une configuration globale, il peut donc y avoir un problème de concurrence si cela se produit dans votre scénario.

16
Jeroen Vannevel

Je ne recommanderais pas de désactiver le chargement paresseux sur une base par demande. Comme AllMadHare le suggère, vous pouvez désactiver complètement le chargement paresseux, mais cela pourrait forcer des changements dans la façon dont vous chargez toutes les données. Je recommanderais de supprimer le mot-clé virtuel des messages pour que votre classe ressemble à ceci:

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

Selon la documentation trouvée ici: https://msdn.Microsoft.com/en-us/data/jj574232.aspx#lazyOffProperty cela vous permettra de charger paresseusement toutes les autres propriétés de navigation et de charger des messages si tu dois.

9
ajliptak

Puisque vous utilisez le chargement différé, vous devez générer des proxys pour vos classes et propriétés de collection.

Remplacer ces propriétés de collection proxy par vos propres collections me semble assez étrange. Vous perdez le suivi des modifications et gagnez probablement quelques autres effets secondaires étranges.

Je recommanderais soit d'utiliser des proxys/chargement paresseux et d'abandonner l'idée de remplacer les collections, soit de ne pas utiliser de proxys et de prendre le contrôle total sur les classes POCO générées.

Laquelle des deux approches convient le mieux à vos besoins dépend de votre utilisation globale du cadre d'entité.

3
Michael Sander