Procedura: gestire transazioni in Entity Framework
In questo argomento viene fornito un esempio di come definire una transazione che coordina l'esecuzione di modifiche agli oggetti in un contesto dell'oggetto con altre operazioni esterne. Per ulteriori informazioni, vedere Gestione di connessioni e transazioni (Entity Framework).
L'esempio incluso in questo argomento è basato sul modello descritto in Modello Sales di AdventureWorks. Per eseguire il codice incluso in questo esempio, è necessario avere già aggiunto il modello Sales di AdventureWorks al progetto e avere configurato il progetto per l'utilizzo di Entity Framework. A tale scopo, completare la procedura descritta in Procedura: utilizzare la procedura guidata Entity Data Model (Entity Framework). È necessario che sia installato anche Microsoft Windows Message Queuing.
Esempio
In questo esempio viene definito un oggetto TransactionScope. TransactionScope garantisce che le modifiche agli oggetti nel contesto dell'oggetto vengano coordinate con una coda di messaggi. Questa transazione viene utilizzata da Entity Framework per salvare le modifiche nel database. Quando si verifica un'eccezione UpdateException, l'operazione viene ritentata fino a due volte. Quando l'operazione ha esito positivo, le modifiche nel contesto dell'oggetto vengono accettate. Per ulteriori informazioni, vedere Gestione di connessioni e transazioni (Entity Framework).
In questo esempio viene utilizzato un contesto dell'oggetto con esecuzione prolungata, eliminato dopo l'esito positivo della transazione o dopo che sono stati eseguiti tutti i tentativi.
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();
}
}
}