如何:在实体框架中管理事务

本主题提供的示例介绍如何定义一个事务,此事务将在对象上下文中对对象进行更改与其他外部操作协调一致。 有关更多信息,请参见管理连接和事务(实体框架)

本主题中的示例基于 AdventureWorks 销售模型。 若要运行本示例中的代码,必须已将 AdventureWorks 销售模型添加到您的项目中,并将项目配置为使用实体框架。 为此,请完成如何:使用实体数据模型向导(实体框架) 中的过程。 还必须安装 Microsoft Windows 消息队列。

示例

此示例定义 TransactionScopeTransactionScope 确保在对象上下文中对对象所做的更改与消息队列协调一致。 当实体框架 将更改保存到数据库时,它将使用此事务。 如果发生 UpdateException,该操作将重试最多两次。 当操作成功时,将接受在对象上下文中所做的更改。 有关更多信息,请参见管理连接和事务(实体框架)

本示例使用长时间运行的对象上下文,当事务获得成功或尝试所有重试之后,将公开此上下文。

Imports System
Imports System.Linq
Imports System.Data
Imports System.Data.Objects
Imports System.Messaging
Imports System.Transactions

Class TransactionSample
    Public Shared Sub EnlistTransaction()
        Dim retries As Integer = 3
        Dim queueName As String = ".\Fulfilling"

        ' Define variables that we need to add an item. 
        Dim quantity As Short = 2
        Dim productId As Integer = 750
        Dim orderId As Integer = 43680

        ' Define a long-running object context. 
        Dim context As New AdventureWorksEntities()

        Dim success As Boolean = False

        ' Wrap the operation in a retry loop. 
        For i As Integer = 0 To retries - 1
            ' Define a transaction scope for the operations. 
            Using transaction As New TransactionScope()
                Try
                    ' Define a query that returns a order by order ID. 
                    Dim order = (From o In context.SalesOrderHeaders _
                        Where o.SalesOrderID = orderId _
                        Select o).First()

                    ' Load items for the order, if not already loaded. 
                    ' Do this if the lazy loading is turned off.
                    If Not order.SalesOrderDetails.IsLoaded Then
                        order.SalesOrderDetails.Load()
                    End If

                    ' Load the customer, if not already loaded. 
                    ' Do this if the lazy loading is turned off.
                    If Not order.ContactReference.IsLoaded Then
                        order.ContactReference.Load()
                    End If

                    ' Create a new item for an existing order. 
                    Dim newItem As SalesOrderDetail = SalesOrderDetail.CreateSalesOrderDetail(0, 0, quantity, productId, 1, 0, _
                    0, 0, Guid.NewGuid(), DateTime.Today)

                    ' Add new item to the order. 
                    order.SalesOrderDetails.Add(newItem)

                    ' Save changes pessimistically. This means that changes 
                    ' must be accepted manually once the transaction succeeds. 
                    context.SaveChanges(SaveOptions.DetectChangesBeforeSave)

                    ' Create the message queue if it does not already exist. 
                    If Not MessageQueue.Exists(queueName) Then
                        MessageQueue.Create(queueName)
                    End If

                    ' Initiate fulfilling order by sending a message. 
                    Using q As New MessageQueue(queueName)
                        Dim msg As New System.Messaging.Message([String].Format("<order customerId='{0}'>" & "<orderLine product='{1}' quantity='{2}' />" & "</order>", order.Contact.ContactID, newItem.ProductID, newItem.OrderQty))

                        ' Send the message to the queue. 
                        q.Send(msg)
                    End Using

                    ' Mark the transaction as complete. 
                    transaction.Complete()
                    success = True
                    Exit Try
                Catch ex As Exception
                    ' Handle errors and deadlocks here and retry if needed. 
                    ' Allow an UpdateException to pass through and 
                    ' retry, otherwise stop the execution. 
                    If ex.[GetType]() <> GetType(UpdateException) Then
                        Console.WriteLine(("An error occured. " & "The operation cannot be retried.") + ex.Message)
                        Exit Try
                        ' If we get to this point, the operation will be retried. 
                    End If
                End Try
            End Using
        Next
        If success Then
            ' Reset the context since the operation succeeded. 
            context.AcceptAllChanges()
        Else
            Console.WriteLine("The operation could not be completed in " & retries & " tries.")
        End If

        ' Dispose the object context. 
        context.Dispose()
    End Sub
End Class
using System;
using System.Linq;
using System.Data;
using System.Data.Objects;
using System.Messaging;
using System.Transactions;

namespace ObjectServicesConceptsCS
{
    class TransactionSample
    {
        public static void EnlistTransaction()
        {
            int retries = 3;
            string queueName = @".\Fulfilling";

            // Define variables that we need to add an item.
            short quantity = 2;
            int productId = 750;
            int orderId = 43680;

            // Define a long-running object context.
            AdventureWorksEntities context
                = new AdventureWorksEntities();

            bool success = false;

            // Wrap the operation in a retry loop.
            for (int i = 0; i < retries; i++)
            {
                // Define a transaction scope for the operations.
                using (TransactionScope transaction = new TransactionScope())
                {
                    try
                    {
                        // Define a query that returns a order by order ID.
                        SalesOrderHeader order =
                        context.SalesOrderHeaders.Where
                        ("it.SalesOrderID = @id", new ObjectParameter(
                         "id", orderId)).First();

                        // Load items for the order, if not already loaded.
                        if (!order.SalesOrderDetails.IsLoaded)
                        {
                            order.SalesOrderDetails.Load();
                        }

                        // Load the customer, if not already loaded.
                        if (!order.ContactReference.IsLoaded)
                        {
                            order.ContactReference.Load();
                        }

                        // Create a new item for an existing order.
                        SalesOrderDetail newItem = SalesOrderDetail.CreateSalesOrderDetail(
                            0, 0, quantity, productId, 1, 0, 0, 0, Guid.NewGuid(), DateTime.Today);

                        // Add new item to the order.
                        order.SalesOrderDetails.Add(newItem);

                        // Save changes pessimistically. This means that changes 
                        // must be accepted manually once the transaction succeeds.
                        context.SaveChanges(SaveOptions.DetectChangesBeforeSave);

                        // Create the message queue if it does not already exist.
                        if (!MessageQueue.Exists(queueName))
                        {
                            MessageQueue.Create(queueName);
                        }

                        // Initiate fulfilling order by sending a message.
                        using (MessageQueue q = new MessageQueue(queueName))
                        {
                            System.Messaging.Message msg =
                                new System.Messaging.Message(String.Format(
                                    "<order customerId='{0}'>" +
                                    "<orderLine product='{1}' quantity='{2}' />" +
                                    "</order>", order.Contact.ContactID,
                                newItem.ProductID, newItem.OrderQty));

                            // Send the message to the queue.
                            q.Send(msg);
                        }

                        // Mark the transaction as complete.
                        transaction.Complete();
                        success = true;
                        break;
                    }
                    catch (Exception ex)
                    {
                        // Handle errors and deadlocks here and retry if needed.
                        // Allow an UpdateException to pass through and 
                        // retry, otherwise stop the execution.
                        if (ex.GetType() != typeof(UpdateException))
                        {
                            Console.WriteLine("An error occured. "
                                + "The operation cannot be retried."
                                + ex.Message);
                            break;
                        }
                        // If we get to this point, the operation will be retried.
                    }
                }
            }
            if (success)
            {
                // Reset the context since the operation succeeded.
                context.AcceptAllChanges();
            }
            else
            {
                Console.WriteLine("The operation could not be completed in "
                    + retries + " tries.");
            }

            // Dispose the object context.
            context.Dispose();
        }
    }
}

另请参见

概念

管理连接和事务(实体框架)