How to: Manage Data Concurrency in the Object Context (Entity Framework)

This topic provides an example of how to manage concurrency in an object context. In this topic, you will generate and handle an OptimisticConcurrencyException when updating the Status property of SalesOrderHeader object. For more information, see Saving Changes and Managing Concurrency (Entity Framework).

The example in this topic is based on the Adventure Works Sales Model. To run the code in this example, you must have already added the AdventureWorks Sales Model to your project and configured your project to use the Entity Framework. To do this, complete the procedures in How to: Manually Configure an Entity Framework Project and How to: Manually Define an Entity Data Model (Entity Framework).

To successfully generate an OptimisticConcurrencyException, you must modify the Status property in the conceptual mapping file.

To enable concurrency checking on the Status property

  1. Open the AdventureWorks.csdl file and locate the definition for the SalesOrderHeader entity.

  2. Find the child Status element, and add the following attribute:

    ConcurrencyMode="fixed"
    
  3. Save changes to AdventureWorks.csdl.

  4. In the following example code, set a breakpoint after the foreach loop (For Each in Visual Basic) and run the application in debug mode.

  5. When the execution breaks, use SQL Server Management Studio to execute the following Transact-SQL command against the AdventureWorks database:

    UPDATE Sales.SalesOrderHeader SET Status = 1 WHERE CreditCardApprovalCode IS NULL.
    
  6. Restart program execution.

Example

In this example, changes to the Status property of the SalesOrderHeader object cause an OptimisticConcurrencyException when the procedure above is followed.

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.SalesOrderHeader.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());
    }
}

See Also

Community Additions

Show: