Partager via


Enregistrement des modifications et gestion de l'accès concurrentiel (Entity Framework)

Par défaut, Entity Framework implémente un modèle d'accès concurrentiel optimiste. Cela signifie que les verrous ne sont pas conservés sur les données dans la source entre le moment où les données sont interrogées et le moment où elles sont mises à jour. Entity Framework enregistre les modifications apportées à l'objet dans la base de données sans vérifier l'accès concurrentiel. Pour les entités qui peuvent connaître un accès concurrentiel de haut niveau, nous recommandons que l'entité définisse une propriété dans la couche conceptuelle avec un attribut ConcurrencyMode="fixed", comme l'illustre l'exemple suivant :

<Property Name="Status" Type="Byte" Nullable="false" ConcurrencyMode="Fixed" />

Lorsque cet attribut est utilisé, Entity Framework recherche les modifications dans la base de données avant de les enregistrer. Toutes les modifications en conflit provoqueront un OptimisticConcurrencyException. Pour plus d'informations, voir Procédure : gérer l'accès concurrentiel aux données dans le contexte de l'objet (Entity Framework). Une exception OptimisticConcurrencyException peut également se produire lorsque vous définissez un modèle EDM (Entity Data Model ) qui met à jour la source de données à l'aide de procédures stockées. Dans ce cas, l'exception est levée lorsque la procédure stockée utilisée pour effectuer des mises à jour signale qu'aucune ligne n'a été mise à jour.

Lorsque vous effectuez des mises à jour dans de tels scénarios à fort accès concurrentiel, nous vous recommandons d'appeler fréquemment Refresh. Lorsque vous appelez Refresh, le RefreshMode contrôle la manière dont les modifications sont propagées. L'option StoreWins spécifiera à Entity Framework de remplacer toutes les données dans le cache d'objet par les valeurs correspondantes dans la base de données. Inversement, l'option ClientWins remplace les valeurs d'origine dans le cache par les valeurs les plus récentes de la source de données. Vous êtes ainsi assuré que toutes les données modifiées dans le cache d'objet peuvent être enregistrées avec succès en retour dans la source de données. Les conflits entre les modifications de données dans le cache et les modifications que vous avez apportées aux mêmes données dans la source de données sont éliminés.

Appelez la méthode Refresh après la méthode SaveChanges si les mises à jour apportées à la source de données sont susceptibles de modifier les données appartenant aux autres objets du contexte d'objet. Par exemple, dans le modèle de vente AdventureWorks Sales Model, lorsqu'un nouveau SalesOrderDetail est ajouté, des déclencheurs metttent à jour la colonne SubTotal pour indiquer le sous-total avec le nouvel élément. Dans ce cas, appelez la méthode Refresh et transmettez l'objet SalesOrderHeader pour la commande. Vous êtes ainsi assuré que les valeurs générées par déclencheur sont renvoyées à l'objet SalesOrderHeader dans le contexte de l'objet.

Entity Framework effectue le suivi des modifications qui ont été apportées aux objets dans le cache. Lorsque la méthode SaveChanges est appelée, Entity Framework tente de fusionner en retour les modifications dans la source de données. SaveChanges peut échouer avec un OptimisticConcurrencyException lorsque les modifications apportées aux données dans le cache de l'objet sont en conflit avec les modifications effectuées dans la source de données une fois que les objets ont été ajoutés au cache ou actualisés dans le cache. Cela entraîne l'annulation de la transaction entière. Lorsqu'une exception OptimisticConcurrencyException se produit, vous devez la traiter en appelant Refresh et en précisant si le conflit doit être résolu en préservant les données dans les données d'objet (ClientWins) ou en mettant à jour le cache d'objet avec les données de la source de données (StoreWins), comme dans l'exemple suivant :

Try
    ' Try to save changes, which may cause a conflict. 
    Dim num As Integer = context.SaveChanges()
    Console.WriteLine("No conflicts. " & num.ToString() & " updates saved.")
Catch generatedExceptionName As OptimisticConcurrencyException
    ' Resolve the concurrency conflict by refreshing the 
    ' object context before re-saving changes. 
    context.Refresh(RefreshMode.ClientWins, orders)

    ' Save changes. 
    context.SaveChanges()
    Console.WriteLine("OptimisticConcurrencyException handled and changes saved")
End Try
try
{
    // Try to save changes, which may cause a conflict.
    int num = context.SaveChanges();
    Console.WriteLine("No conflicts. " +
        num.ToString() + " updates saved.");
}
catch (OptimisticConcurrencyException)
{
    // Resolve the concurrency conflict by refreshing the 
    // object context before re-saving changes. 
    context.Refresh(RefreshMode.ClientWins, orders);

    // Save changes.
    context.SaveChanges();
    Console.WriteLine("OptimisticConcurrencyException "
    + "handled and changes saved");
}

SaveChanges peut générer une exception UpdateException lorsqu'un objet ajouté à ObjectContext ne peut pas être créé dans la source de données. Cela peut se produire si une ligne associée à la clé étrangère spécifiée par la relation existe déjà. Dans ce cas, vous ne pouvez pas utiliser Refresh pour mettre à jour l'objet ajouté dans le contexte de l'objet. À la place, rechargez l'objet avec une valeur de OverwriteChanges pour MergeOption.

Pour plus d'informations sur la gestion du contexte de l'objet, consultez Procédure : gérer l'accès concurrentiel aux données dans le contexte de l'objet (Entity Framework).

Vous pouvez choisir d'utiliser des transactions comme alternative à l'accès concurrentiel optimiste. Pour plus d'informations, consultez Gestion des connexions et des transactions (Entity Framework).

Dans cette section

Procédure : gérer l'accès concurrentiel aux données dans le contexte de l'objet (Entity Framework)

Voir aussi

Concepts

Utilisation d'objets (Entity Framework)
Création, ajout, modification et suppression d'objets (Entity Framework)