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

Cette rubrique fournit un exemple de gestion de l'accès concurrentiel dans le contexte d'un objet. Dans cette rubrique, vous allez générer et gérer un objet OptimisticConcurrencyException lors de la mise à jour de la propriété Status de l'objet SalesOrderHeader. Pour plus d'informations, voir Enregistrement des modifications et gestion de l'accès concurrentiel (Entity Framework).

L'exemple de cette rubrique est basé sur le modèle de vente Adventure Works Sales Model. Pour exécuter le code de cet exemple, vous devez déjà avoir ajouté le modèle de vente AdventureWorks Sales Model à votre projet et configuré ce dernier pour qu'il utilise Entity Framework. Pour ce faire, exécutez les procédures décrites dans Procédure : configurer manuellement un projet Entity Framework et Procédure : définir manuellement les fichiers du modèle et les fichiers de mappage (Entity Framework).

Pour générer correctement un objet OptimisticConcurrencyException, vous devez modifier la propriété Status dans le fichier de mappage conceptuel.

Pour activer la vérification de l'accès concurrentiel sur la propriété Status

  1. Ouvrez le fichier AdventureWorks.csdl et recherchez la définition de l'entité SalesOrderHeader.

  2. Trouvez l'élément Status enfant et ajoutez l'attribut suivant :

    ConcurrencyMode="fixed"
    
  3. Enregistrez les modifications apportées à AdventureWorks.csdl.

  4. Dans l'exemple de code ci-dessous, définissez un point d'arrêt après la boucle foreach (For Each en Visual Basic) et exécutez l'application en mode débogage.

  5. Lorsque l'exécution s'arrête, utilisez SQL Server Management Studio pour exécuter la commande Transact-SQL suivante sur la base de données AdventureWorks :

    UPDATE Sales.SalesOrderHeader SET Status = 1 WHERE CreditCardApprovalCode IS NULL.
    
  6. Redémarrez l'exécution du programme.

Exemple

Dans cet exemple, les modifications apportées à la propriété Status de l'objet SalesOrderHeader génèrent un objet OptimisticConcurrencyException lorsque la procédure ci-dessus est suivie.

Using context As New AdventureWorksEntities()
    Try
        ' Perform an operation with a high-level of concurrency. 
        ' Change the status of all orders without an approval code. 
        Dim orders As ObjectQuery(Of SalesOrderHeader) = context.SalesOrderHeaders.Where("it.CreditCardApprovalCode IS NULL").Top("100")

        For Each order As SalesOrderHeader In orders
            ' Reset the order status to 4 = Rejected. 
            order.Status = 4
        Next
        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

        For Each order As SalesOrderHeader In orders
            Console.WriteLine(("Order ID: " & order.SalesOrderID.ToString() & " Order status: ") + order.Status.ToString())
        Next
    Catch ex As UpdateException
        Console.WriteLine(ex.ToString())
    End Try
End Using
using (AdventureWorksEntities context =
    new AdventureWorksEntities())
{
    try
    {
        // Perform an operation with a high-level of concurrency.
        // Change the status of all orders without an approval code.
        ObjectQuery<SalesOrderHeader> orders =
            context.SalesOrderHeaders.Where(
            "it.CreditCardApprovalCode IS NULL").Top("100");

        foreach (SalesOrderHeader order in orders)
        {
            // Reset the order status to 4 = Rejected.
            order.Status = 4;
        }
        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");
        }

        foreach (SalesOrderHeader order in orders)
        {
            Console.WriteLine("Order ID: " + order.SalesOrderID.ToString()
                + " Order status: " + order.Status.ToString());
        }
    }
    catch (UpdateException ex)
    {
        Console.WriteLine(ex.ToString());
    }
}

Voir aussi

Concepts

Utilisation d'objets (Entity Framework)