Telerik OpenAccess Classic

Telerik OpenAccess ORM Send comments on this topic.
How to: Manage ObjectScope using System.Transactions Namespace
Programmer's Guide > OpenAccess ORM Classic (Old API) > OpenAccess Tasks > How to: Manage ObjectScope using System.Transactions Namespace

Glossary Item Box

This documentation article is a legacy resource describing the functionality of the deprecated OpenAccess Classic only. The contemporary documentation of Telerik OpenAccess ORM is available here.

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")
  ' Use the passed style for the transaction provider to obtain an object scope.
  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()
  ' Transaction is started, object scope must be set to participate
  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.