Partager via


Enregistrement de données

Bien que l'interrogation vous permette de lire des données à partir de la base de données, sauvegarder des données signifie ajouter de nouvelles entités à la base de données, supprimer des entités ou modifier de quelque manière que ce soit les propriétés des entités existantes. Entity Framework Core (EF Core) prend en charge deux approches fondamentales pour enregistrer des données dans la base de données.

Approche 1 : suivi des modifications et SaveChanges

Dans de nombreux scénarios, votre programme doit interroger certaines données de la base de données, effectuer une modification sur celle-ci et enregistrer ces modifications à nouveau ; il s’agit parfois d’une « unité de travail ». Par exemple, supposons que vous disposez d’un ensemble de blogs et que vous souhaitez modifier la Url propriété de l’une d’entre elles. Dans EF, cela se fait généralement comme suit :

using (var context = new BloggingContext())
{
    var blog = await context.Blogs.SingleAsync(b => b.Url == "http://example.com");
    blog.Url = "http://example.com/blog";
    await context.SaveChangesAsync();
}

Le code ci-dessus effectue les étapes suivantes :

  1. Il utilise une requête LINQ standard pour charger une entité à partir de la base de données (voir Données de requête). Les requêtes d’EF sont suivies par défaut, ce qui signifie qu’EF effectue le suivi des entités chargées dans son suivi des modifications internes.
  2. L’instance d’entité chargée est manipulée comme d’habitude, en affectant une propriété .NET. EF n’est pas impliqué dans cette étape.
  3. Enfin, DbContext.SaveChanges() est appelé. À ce stade, EF détecte automatiquement les modifications en comparant les entités à un instantané à partir du moment où elles ont été chargées. Toutes les modifications détectées sont conservées dans la base de données ; lors de l’utilisation d’une base de données relationnelle, cela implique généralement l’envoi d’un sql UPDATE pour mettre à jour les lignes pertinentes.

Notez que l’opération de mise à jour décrite ci-dessus décrit une opération de mise à jour classique pour les données existantes, mais des principes similaires sont en vigueur pour l’ajout et la suppression d’entités . Vous interagissez avec le suivi des modifications d’EF en appelant DbSet<TEntity>.Add et Removeen provoquant le suivi des modifications. EF applique ensuite toutes les modifications suivies à la base de données lorsqu’elle SaveChanges() est appelée (par exemple, via SQL INSERT et DELETE lors de l’utilisation d’une base de données relationnelle).

SaveChanges() offre les avantages suivants :

  • Vous n’avez pas besoin d’écrire du code pour suivre les entités et les propriétés modifiées . EF effectue cette opération automatiquement pour vous, et met à jour uniquement ces propriétés dans la base de données, ce qui améliore les performances. Imaginez si vos entités chargées sont liées à un composant d’interface utilisateur, ce qui permet aux utilisateurs de modifier les propriétés qu’ils souhaitent ; EF enlève le fardeau de déterminer quelles entités et propriétés ont été réellement modifiées.
  • L’enregistrement des modifications dans la base de données peut parfois être compliqué ! Par exemple, si vous souhaitez ajouter un blog et certains billets pour ce blog, vous devrez peut-être récupérer la clé générée par la base de données pour le blog inséré avant de pouvoir insérer les billets (car ils doivent faire référence au blog). EF fait tout cela pour vous, enlevant la complexité.
  • EF peut détecter les problèmes d’accès concurrentiel, par exemple lorsqu’une ligne de base de données a été modifiée par quelqu’un d’autre entre votre requête et SaveChanges(). Des détails supplémentaires sont disponibles dans les conflits de concurrence.
  • Sur les bases de données qui la prennent en charge, SaveChanges() encapsule automatiquement plusieurs modifications dans une transaction, ce qui garantit que vos données restent cohérentes si une défaillance se produit. Vous trouverez plus de détails dans Transactions.
  • SaveChanges() regroupe également plusieurs modifications dans de nombreux cas, réduisant considérablement le nombre d’allers-retours de base de données et améliorant considérablement les performances. Pour plus d’informations, consultez La mise à jour efficace.

Pour plus d’informations et des exemples de code sur l’utilisation de base SaveChanges() , consultez SaveChanges de base. Pour plus d’informations sur le suivi des modifications d’EF, consultez la vue d’ensemble du suivi des modifications.

Approche 2 : ExecuteUpdate et ExecuteDelete (« mise à jour en bloc »)

Bien que le suivi des modifications et SaveChanges() soit un moyen puissant d’enregistrer les modifications, ils présentent certains inconvénients.

Tout d’abord, SaveChanges() vous devez interroger et suivre toutes les entités que vous allez modifier ou supprimer. Si vous devez, par exemple, supprimer tous les blogs avec une évaluation inférieure à un certain seuil, vous devez interroger, matérialiser et suivre un nombre potentiellement énorme de lignes et faire en sorte que SaveChanges() génère une DELETE déclaration pour chacun d'eux. Les bases de données relationnelles offrent une alternative beaucoup plus efficace : une seule DELETE commande peut être envoyée, en spécifiant les lignes à supprimer via une WHERE clause, mais le SaveChanges() modèle ne permet pas de générer cela.

Pour prendre en charge ce scénario de « mise à jour en bloc », vous pouvez utiliser ExecuteDelete comme suit :

context.Blogs.Where(b => b.Rating < 3).ExecuteDelete();

Cela vous permet d’exprimer une instruction SQL DELETE via des opérateurs LINQ standard , similaires à une requête LINQ standard, ce qui entraîne l’exécution du code SQL suivant sur la base de données :

DELETE FROM [b]
FROM [Blogs] AS [b]
WHERE [b].[Rating] < 3

Cela s’exécute très efficacement dans la base de données, sans charger de données à partir de la base de données ou impliquant le suivi des modifications d’EF. De même, ExecuteUpdate vous permet d'exprimer une instruction SQL UPDATE.

Même si vous ne modifiez pas d’entités en bloc, vous savez peut-être exactement quelles propriétés de l’entité que vous souhaitez modifier. L’utilisation de l’API de suivi des modifications pour effectuer la modification peut être trop complexe, nécessitant la création d’une instance d’entité, le suivi via Attach, l’exécution de vos modifications et enfin l’appel SaveChanges(). Pour ces scénarios, ExecuteUpdate et ExecuteDelete peuvent être un moyen considérablement plus simple d’exprimer la même opération.

Enfin, le suivi des modifications et SaveChanges() lui-même imposent une certaine surcharge d’exécution. Si vous écrivez une application à hautes performances, ExecuteUpdate et ExecuteDelete vous permettent d’éviter ces deux composants et de générer efficacement l’instruction souhaitée.

Toutefois, notez que ExecuteUpdate et ExecuteDelete présentent également certaines limitations :

  • Ces méthodes s’exécutent immédiatement et ne peuvent pas être traitées par lots avec d’autres opérations. D’autre part, SaveChanges() permet de regrouper plusieurs opérations.
  • Étant donné que le suivi des modifications n’est pas impliqué, il vous incombe de savoir exactement quelles entités et propriétés doivent être modifiées. Cela peut impliquer davantage de code manuel et de bas niveau pour suivre ce qui doit être modifié et ce qui ne doit pas l’être.
  • De plus, étant donné que le suivi des modifications n’est pas impliqué, ces méthodes n’appliquent pas automatiquement le contrôle d’accès concurrentiel lors de la persistance des modifications. Toutefois, vous pouvez toujours ajouter explicitement une clause pour implémenter vous-même le Where contrôle de concurrence.
  • Actuellement, seules la mise à jour et la suppression sont prises en charge. Pour l’insertion, vous devez utiliser DbSet<TEntity>.Add et SaveChanges().

Pour plus d’informations et d’exemples de code, consultez ExecuteUpdate et ExecuteDelete.

Résumé

Voici quelques instructions pour savoir quand utiliser cette approche. Notez que ces règles ne sont pas absolues, mais fournissent des règles utiles :

  • Si vous ne savez pas à l’avance quelles modifications auront lieu, utilisez SaveChanges; elle détecte automatiquement les modifications à appliquer. Exemples de scénarios :
    • « Je souhaite charger un blog à partir de la base de données et afficher un formulaire permettant à l’utilisateur de le modifier »
  • Si vous devez manipuler un graphique d’objets (c’est-à-dire plusieurs objets interconnectés), utilisez SaveChanges; il détermine l’ordre approprié des modifications et comment lier tout ensemble.
    • « Je veux mettre à jour un blog, modifier certains de ses billets et supprimer d’autres »
  • Si vous souhaitez modifier un grand nombre d’entités en fonction de certains critères, utilisation ExecuteUpdate et ExecuteDelete. Exemples de scénarios :
    • « Je veux donner à tous les employés une augmentation »
    • « Je veux supprimer tous les blogs dont le nom commence par X »
  • Si vous connaissez déjà exactement les entités que vous souhaitez modifier et comment vous souhaitez les modifier, utilisez ExecuteUpdate et ExecuteDelete. Exemples de scénarios :
    • « Je veux supprimer le blog dont le nom est 'Foo' »
    • « Je veux changer le nom du blog avec l’ID 5 en « Bar »