The System.Transaction namespace contains classes that allow you to create and participate in a transaction (local or distributed) with one or multiple participants. The following section provides you with a walkthrough of the System.Transaction Example. This example demonstrates the differences when System.Transactions are used as transaction boundary markers.
This example will only work in .NET 2.0 since System.Transactions is new to .NET 2.0. System.Transactions significantly improves support for distributed transactions (refer to System.Transactions for more information).
To mark transaction boundaries it is necessary to specify the style used up front; this is done with the help of the three TransactionProviders mentioned below:

|
|
OpenAccess ORM is the default TransactionProvider. It indicates the usage of built-in database transactions provided by OpenAccess. These transactions can be accessed via the Transaction property. In this case, once the transaction is started, the objectscope implicitly participates with it. |

|
|
TransactionScope requires the usage of the System.Transactions namespace. This is based on an implicit model, and uses the TransactionScope class. It is recommended to use this model, since the transactions are automatically managed by the infrastructure, i.e., it is not necessary to explicitly enlist the objectscope to work with a transaction. |

|
|
Explicit also requires the usage of the System.Transactions namespace. This is based on an explicit model, and uses the System.Transaction.Transaction or one of its subclasses, such as, CommittableTransaction. Here, the objectscope needs to be manually managed, i.e., they will need to be manually enlisted in a transaction context. |
The usage of the System.Transactions namespace requires that the System.Transactions assembly be added in your project.
The example demonstrates the usage of all the above models, i.e., The OpenAccess ORM Model, The Implicit (TransactionScope) Model and The Explicit model, and the differences while marking transaction boundaries for each of them.
The class, i.e., MyClass used in this example is the same as used in First Example.
This example uses a common method to open the database and obtain an object scope. This method is used by all the models:
C# |
Copy Code |
protected void ObtainScope(TransactionProvider p) { Database db = Database.Get("MssqlConnection1"); // Use the passed style for the transaction provider to obtain an object scope.
db.Properties.TransactionProvider = p; myObjectScope = db.GetObjectScope(); } |
Example Title |
Copy Code |
Protected Sub ObtainScope(ByVal p As TransactionProvider) Dim db As Database = Database.Get("MssqlConnection1") db.Properties.TransactionProvider = p myObjectScope = db.GetObjectScope() End Sub |
Using the OpenAccess ORM Model
The normal OpenAccess ORM way to mark transaction boundaries is shown in this method.
C# |
Copy Code |
internal class WithOpenAccess ORM : Program { internal WithOpenAccess ORM() { ObtainScope(TransactionProvider.OpenAccess ORM); } |
VB.NET |
Copy Code |
Friend Class WithOpenAccess ORM Inherits Program Friend Function ORM() As WithOpenAccess ObtainScope(TransactionProvider.OpenAccess ORM) End Function |
Opening the database using OpenAccess ORM transaction boundary markers:
C# |
Copy Code |
ObtainScope(TransactionProvider.OpenAccess ORM); |
VB.NET |
Copy Code |
ObtainScope(TransactionProvider.OpenAccess ORM) |
Storing new objects in MyClass:
C# |
Copy Code |
protected override void Action() { myObjectScope.Transaction.Begin(); { MyClass obj = new MyClass(); obj._string = "OpenAccess-" + DateTime.Now.ToString(); ; myObjectScope.Add(obj); } myObjectScope.Transaction.Commit(); |
VB.NET |
Copy Code |
Protected Overrides Sub Action() myObjectScope.Transaction.Begin() Dim obj As New [MyClass]() obj._string = "OpenAccess-" & DateTime.Now.ToString() myObjectScope.Add(obj) myObjectScope.Transaction.Commit() |
Once you Begin() a transaction, the objectscope implicitly participates with it:
C# |
Copy Code |
myObjectScope.Transaction.Begin(); |
VB.NET |
Copy Code |
myObjectScope.Transaction.Begin(); |
Creating a new object of MyClass:
C# |
Copy Code |
MyClass obj = new MyClass(); |
VB.NET |
Copy Code |
Dim obj As New [MyClass]() |
Making the object persistent:
C# |
Copy Code |
myObjectScope.Add(obj); |
VB.NET |
Copy Code |
myObjectScope.Add(obj) |
Committing the transaction:
C# |
Copy Code |
myObjectScope.Transaction.Commit(); |
VB.NET |
Copy Code |
myObjectScope.Transaction.Commit() |
Retrieving the persistent MyClass objects:
The query given below returns all the stored instances of MyClass:
C# |
Copy Code |
myObjectScope.Transaction.Begin(); { IQueryResult result = myObjectScope.GetOqlQuery("SELECT * FROM MyClassExtent").Execute() ...... |
VB.NET |
Copy Code |
myObjectScope.Transaction.Begin() Dim result As IQueryResult = myObjectScope.GetOqlQuery("SELECT * FROM MyClassExtent").Execute() ...... |
The transaction must be terminated, either by Commit() or Rollback(), before the modifications can be copied back to the database. Here, it has been explicitly rolledback:
C# |
Copy Code |
myObjectScope.Transaction.Rollback(); |
VB.NET |
Copy Code |
myObjectScope.Transaction.Rollback() |
As shown above, while using the OpenAccess ORM model, which is also the default method, it is only necessary to begin a transaction, i.e., there is no need to enlist the objectscope to participate in a transaction.
 |
In case of TransactionProvider.OpenAccess ORM it is not possible for the objectscope to enlist in System.Transactions. |
Using the TransactionScope Model
This method shows how to use System.Transaction.TransactionScope as a transaction boundary with OpenAccess.
C# |
Copy Code |
internal class WithTransactionScope : Program { internal WithTransactionScope() { ObtainScope(TransactionProvider.TransactionScope); } |
VB.NET |
Copy Code |
Friend Class WithTransactionScope Inherits Program Friend Sub New() ObtainScope(TransactionProvider.TransactionScope) End Sub |
Opening the database using transactionscope as an implicit transaction boundary marker:
C# |
Copy Code |
ObtainScope(TransactionProvider.TransactionScope); |
VB.NET |
Copy Code |
ObtainScope(TransactionProvider.TransactionScope) |
Storing new objects in MyClass:
In this case, once the connection is opened, the transaction gets automatically enlisted in the current transaction scope:
C# |
Copy Code |
protected override void Action() { using (TransactionScope txnScope = new TransactionScope()) ..... |
VB.NET |
Copy Code |
Protected Overrides Sub Action() Using txnScope As New TransactionScope() ..... |
Next, we have created a new object of MyClass, made it persistent and then committed the transaction :
C# |
Copy Code |
{ MyClass obj = new MyClass(); obj._string = "Scope-" + DateTime.Now.ToString(); ; myObjectScope.Add(obj);
txnScope.Complete(); } |
VB.NET |
Copy Code |
Dim obj As New [MyClass]() obj._string = "Scope-" & DateTime.Now.ToString() myObjectScope.Add(obj) txnScope.Complete() |
Retrieving the persistent MyClass objects:
The query given below returns all the stored instances of MyClass:
C# |
Copy Code |
using (TransactionScope txnScope1 = new TransactionScope()) { IQueryResult result = myObjectScope.GetOqlQuery("SELECT * FROM MyClassExtent").Execute() ...... |
VB.NET |
Copy Code |
Using txnScope1 As New TransactionScope() Dim result As IQueryResult = myObjectScope.GetOqlQuery("SELECT * FROM MyClassExtent").Execute() ...... |
In this case, it is not necessary to explicitly end the transaction, since the using statement is used. The using statement defines the scope within which an object or objects will be active and will also call the Dispose() method when the IDisposable interface is implemented. The TransactionScope is an IDisposable and so it is disposed upon leaving the using block.
As shown above, while using the TransactionScope model it is only necessary to begin a transaction, i.e., there is no need to enlist the objectscope to participate in a transaction. Also, there is no need to explicitly end the transaction, while retrieving the objects, since the Dispose() method of the TransactionScope instance actively commits the transaction when called on a completed transaction. This is a deviation from the normal Dispose() pattern!
Using the Explicit Model
This method shows how to use System.Transaction.CommittableTransaction as a transaction boundary with OpenAccess.
C# |
Copy Code |
internal class WithExplicitTransactions : Program { internal WithExplicitTransactions() { ObtainScope(TransactionProvider.Explicit); } |
VB.NET |
Copy Code |
Friend Class WithExplicitTransactions Inherits Program Friend Sub New() ObtainScope(TransactionProvider.Explicit) End Sub |
Opening the database using a CommittableTransaction as explicit transaction boundary marker:
C# |
Copy Code |
ObtainScope(TransactionProvider.Explicit); |
VB.NET |
Copy Code |
ObtainScope(TransactionProvider.Explicit) |
Storing new objects in MyClass:
In this case, it is necessary to manually enlist a connection into the transaction and then commit the transaction. That is, the ObjectScope needs to be explicitly told to work with a transaction, by calling the EnlistTransaction() method:
C# |
Copy Code |
protected override void Action() { using (CommittableTransaction txn = new CommittableTransaction()) { myObjectScope.EnlistTransaction(txn); ..... |
VB.NET |
Copy Code |
Protected Overrides Sub Action() Using txn As New CommittableTransaction() myObjectScope.EnlistTransaction(txn) ..... |
Next, we have created a new object of MyClass, made it persistent and then committed the transaction :
C# |
Copy Code |
.... MyClass obj = new MyClass(); obj._string = "Commitable-" + DateTime.Now.ToString(); ; myObjectScope.Add(obj);
txn.Commit(); } |
VB.NET |
Copy Code |
.... MyClass obj = New [MyClass]() obj._string = "Commitable-" & DateTime.Now.ToString() myObjectScope.Add(obj) txn.Commit() } |
Retrieving the persistent MyClass objects:
The query given below returns all the stored instances of MyClass:
C# |
Copy Code |
using (CommittableTransaction txn1 = new CommittableTransaction()) { // Transaction is started, object scope must be set to participate myObjectScope.EnlistTransaction(txn1);
IQueryResult result = myObjectScope.GetOqlQuery("SELECT * FROM MyClassExtent").Execute() ...... |
VB.NET |
Copy Code |
Using txn1 As New CommittableTransaction() myObjectScope.EnlistTransaction(txn1) Dim result As IQueryResult = myObjectScope.GetOqlQuery("SELECT * FROM MyClassExtent").Execute() ...... |
In this case also, it is not necessary to explicitly end the transaction, since the using statement is used. The CommittableTransaction is an IDisposable and so it is disposed upon leaving the using block, as explained above, in the TransactionScope Model section.
As shown in this example, while using the Explicit model it is necessary to manually enlist the objectscope to participate in a transaction. And you must call Commit() explicitly (which does all the database work) in order to store the objects.
 |
If you run into timeout problems, use the transaction constructors with a larger time span set. |