web-dev-qa-db-fra.com

Chargement désireux, paresseux et explicite dans EF6

J'ai lu ceci tutoriel et cela article mais je ne comprends pas exactement l'utilisation de chaque type de chargement.

J'explique

J'ai ce POCO:

public partial class dpc_gestion
{
    public dpc_gestion()
    {
        this.ass_reunion_participant = new HashSet<ass_reunion_participant>();
        this.dpc_participant = new HashSet<dpc_participant>();
        this.dpc_reunion = new HashSet<dpc_reunion>();
    }

    public int dpc_id_pk { get; set; }
    public Nullable<int> dpc_id_gdp_fk { get; set; }
    public Nullable<int> dpc_id_theme { get; set; }
    public int dpc_id_animateur_fk { get; set; }
    public Nullable<System.DateTime> dpc_date_creation { get; set; }
    public Nullable<System.DateTime> dpc_date_fin { get; set; }
    public Nullable<System.DateTime> dpc_date_engag_anim { get; set; }
    public Nullable<bool> dpc_flg_let_engag_anim { get; set; }
    public Nullable<bool> dpc_flg_fsoins_anim { get; set; }
    public virtual ICollection<ass_reunion_participant> ass_reunion_participant { get; set; }
    public virtual theme_dpc theme_dpc { get; set; }
    public virtual gdp_groupe_de_pair gdp_groupe_de_pair { get; set; }
    public virtual ICollection<dpc_participant> dpc_participant { get; set; }
    public virtual ICollection<dpc_reunion> dpc_reunion { get; set; }
}

J'ai compris ça:

  1. Pour le chargement paresseux : parce que le chargement est paresseux, si j'appelle le dbset dpc_gestion toutes les propriétés de navigation ne seront pas chargées. Ce type de chargement est le meilleur en termes de performances et de réactivité. Il est activé par défaut et si je souhaite le réactiver, je dois définir:

    context.Configuration.ProxyCreationEnabled = true;    
    context.Configuration.LazyLoadingEnabled = true;
    
  2. Pour le chargement avide Ce n'est pas paresseux: il a chargé toutes les propriétés de navigation quand je charge dpc_gestion. Les propriétés de navigation peuvent être chargées à l'aide de la méthode include. Pour activer ce type de chargement:

    context.Configuration.LazyLoadingEnabled = false;
    
  3. Pour le chargement explicite C'est comme le chargement enthousiaste mais nous utilisons la méthode Load au lieu de include.

J'aimerais donc savoir:

  1. Si ce petit CV est vrai?
  2. Si c'est vrai, quelle est la différence entre un chargement enthousiaste et explicite?
  3. Si j'utilise le chargement paresseux et j'appelle par exemple dpc_gestion.dpc_participant, les propriétés de navigation se chargent-elles ou j'obtiendrai une exception?
  4. Existe-t-il un cas où un chargement rapide ou un chargement explicite étaient meilleurs qu'un chargement paresseux en termes de performances et de réactivité?

Merci

24
Lamloumi Afif

Si ce petit CV est vrai?

Oui.

Si c'est vrai, quelle est la différence entre un chargement enthousiaste et explicite?

Le chargement avide est l'opposé de Le chargement paresseux mais Le chargement explicite est similaire au chargement paresseux , sauf que : vous récupérez explicitement les données associées dans le code; cela ne se produit pas automatiquement lorsque vous accédez à une propriété de navigation. Vous chargez les données associées manuellement en obtenant l'entrée du gestionnaire d'état d'objet pour une entité et en appelant le Collection.Load méthode pour les collections ou Reference.Load méthode pour les propriétés qui contiennent une seule entité.

De techblog :

Chargement avide:

Le chargement désireux est l'opposé de Le chargement paresseux qui est: Le processus de chargement d'un ensemble spécifique d'objets liés avec les objets qui ont été explicitement demandés dans la requête .

Chargement explicite:

Le chargement explicite est défini comme suit: lorsque des objets sont renvoyés par une requête, les objets associés ne sont pas chargés en même temps. Par défaut, ils ne sont chargés que lorsqu'ils sont explicitement demandés à l'aide de la méthode Load sur une propriété de navigation.

Et:

Si j'utilise le chargement paresseux et j'appelle par exemple dpc_gestion.dpc_participant, les propriétés de navigation se chargent-elles ou j'obtiendrai une exception?

Vous n'obtenez aucune exception et les propriétés de navigation devraient se charger.

Existe-t-il un cas où un chargement rapide ou un chargement explicite étaient meilleurs qu'un chargement paresseux en termes de performances et de réactivité?

Le chargement avide est généralement plus efficace lorsque vous avez besoin des données associées pour toutes les lignes récupérées de la table principale. Et aussi lorsque les relations ne sont pas trop, un chargement rapide sera une bonne pratique pour réduire les requêtes supplémentaires sur le serveur. Mais quand vous savez que vous n'aurez pas besoin d'une propriété instantanément, alors le chargement paresseux peut être un bon choix. Et le chargement enthousiaste est également un bon choix dans une situation où votre contexte db serait supprimé et le chargement paresseux ne pourrait plus avoir lieu. Par exemple, considérez ce qui suit:

public List<Auction> GetAuctions()
{
    using (DataContext db = new DataContext())
    {
        return db.Auctions.ToList();
    }
}

Après avoir appelé cette méthode, vous ne pouvez pas charger l'entité associée paresseusement car le db est supprimé et donc le Eager Loading serait un meilleur choix ici.

Une autre chose à noter est la suivante: Le chargement paresseux produira plusieurs requêtes SQL tandis que Le chargement désireux charger des données avec une seule demande. Un chargement avide est également un bon choix pour résoudre le problème de sélection n + 1 dans les ORM. Jetez un oeil à ce post: Quel est le problème des sélections n + 1?

21
Salah Akbari

questions 1 et 2:

Votre explication de chargement paresseux et chargement rapide est correcte.
L'utilisation de chargement explicite est un peu différente de celle que vous avez décrite.

EntityFramework renvoie IQueryable objets, qui contiennent essentiellement la requête dans la base de données. Mais ceux-ci ne sont exécutés que la première fois qu'ils sont énumérés.
Load exécute la requête afin que ses résultats soient stockés localement.
Appeler Load revient au même que d'appeler ToList et de jeter ce List, sans avoir la surcharge de créer le List.

Question 3:

Si vous utilisez le chargement différé, EntityFramework se chargera de charger la propriété de navigation pour vous, vous n'aurez donc pas d'exception.
Gardez à l'esprit que cela peut prendre un certain temps et que votre application ne réponde pas .

Question 4:

Dans les cas déconnectés (par exemple, application réseau), vous ne pouvez pas utiliser chargement paresseux, car ces objets sont traduits en DTO, puis non suivi par EntityFramework.

De plus, si vous savez que vous allez utiliser un propriété de navigation, il est recommandé de le charger avec impatience, vous n'avez donc pas à attendre qu'il soit chargé à partir de la base de données.
Par exemple, supposons que vous stockiez le résultat dans une liste et que vous le liez à un WPF DataGrid. Si le DataGrid accède à une propriété qui n'est pas encore chargée, l'utilisateur connaît un délai d'attente notable jusqu'à ce que cette propriété s'affiche. De plus, l'application ne répondra pas pendant le temps de chargement (si vous ne chargez pas de manière asynchrone).

6
Domysee

Ici, vous apprendrez à charger explicitement des entités liées dans un graphique d'entité. Le chargement explicite est valide dans EF 6 et EF Core à la fois.

Même avec le chargement paresseux désactivé (dans EF 6), il est toujours possible de charger paresseusement des entités liées, mais cela doit être fait avec un appel explicite. Utilisez la méthode Load() pour charger explicitement les entités liées. Prenons l'exemple suivant.

using (var context = new SchoolContext())
{
     var student = context.Students
                              .Where(s => s.FirstName == "Bill")
                             .FirstOrDefault<Student>();

     context.Entry(student).Reference(s => s.StudentAddress).Load(); 
     // loads StudentAddress
     context.Entry(student).Collection(s => s.StudentCourses).Load(); 
     // loads Courses collection      
}

Dans l'exemple ci-dessus, context.Entry(student).Reference(s => s.StudentAddress).Load() charge l'entité StudentAddress. La méthode Reference() est utilisée pour obtenir un objet de la propriété de navigation de référence spécifiée et la méthode Load() le charge explicitement.

De la même manière, context.Entry(student).Collection(s => s.Courses).Load() charge la propriété de navigation de collection Courses de l'entité Student. La méthode Collection() obtient un objet qui représente la propriété de navigation de la collection.

La méthode Load() exécute la requête SQL dans la base de données pour obtenir les données et remplir la propriété de référence ou de collection spécifiée dans la mémoire, comme illustré ci-dessous. enter image description here
Query (): Vous pouvez également écrire des requêtes LINQ-to-Entities pour filtrer les données associées avant le chargement. La méthode Query () nous permet d'écrire d'autres requêtes LINQ pour les entités liées afin de filtrer les données liées.

using (var context = new SchoolContext())
{
    var student = context.Students
                    .Where(s => s.FirstName == "Bill")
                    .FirstOrDefault<Student>();

    context.Entry(student)
             .Collection(s => s.StudentCourses)
               .Query()
            .Where(sc => sc.CourseName == "Maths")
            .FirstOrDefault();
}     

Dans l'exemple ci-dessus, .Collection(s => s.StudentCourses).Query() nous permet d'écrire d'autres requêtes pour l'entité StudentCourses.

1
Ghulam Dastgeer