Getting the Transaction for an Object Scope
All operations for a transaction are accessible through the OpenAccess.ITransaction interface. The ITransaction instance for a given object scope can be obtained by the IObjectScope.Transaction property. There is a one-to-one relationship between an object scope and a transaction; each IObjectScope instance has one implicitly defined ITransaction. The ITransaction instance does not change until IObjectScope.Dispose() is explicitly called. It is legal to use an ITransaction reference, as shown in the following example, rather than always accessing the Transaction property of the object scope.
In this example below, the ITransaction associated with the object scope is stored in a variable that can be used later in the application code.
| C# |
Copy Code |
|
IObjectScope scope = ObjectScopeProvider1.GetNewObjectScope(); ITransaction txn = scope.Transaction; |
| VB.NET |
Copy Code |
|
Dim scope As IObjectScope = ObjectScopeProvider1.GetNewObjectScope() Dim txn As ITransaction = scope.Transaction |
Begin, Commit
Before you can perform any operations on persistent class instances, you need to start a transaction. This is done with the ITransaction.Begin() method. Any modifications made to objects after beginning the transaction can be persistently written into the database by calling ITransaction.Commit(). The Commit() call attempts to write all modified objects into the database. If any error occurs, no modifications you have made since the Begin() call are written (atomicity principle).
In the following example, a new Customer object is stored in the database.
| C# |
Copy Code |
|
scope.Transaction.Begin(); Customer c = new Customer(); c.Name = "Smith"; c.CustomerNo = 34567; //the customer is added to the object scope . . . scope.Add(c); // here, the transaction is committed and // all new and modified objects are stored scope.Transaction.Commit(); |
| VB.NET |
Copy Code |
|
scope.Transaction.Begin() Dim c As New Customer() c.Name = "Smith" c.CustomerNo = 34567
scope.Add(c)
scope.Transaction.Commit() |
If you need the in-memory objects to keep their values following a commit, you can use the transaction property RetainValues. This might be necessary if you want to access the objects from outside a transaction. The Transaction Properties section discusses this further.
Rollback
If, for some reason, you decide that the changes made within the transaction should not be made persistent, you can end the transaction with the Rollback() method and no changes will be written to the database.
The following example depends on user input to determine whether the name change to a Customer instance will be made persistent. The OK button results in a Commit() call, which attempts to write all modified objects into the database. The Cancel button results in a Rollback() call, which ends the transaction and no changes will be written to the database.
| C# |
Copy Code |
|
scope.Transaction.Begin(); // retrieve Customer instance from the database Customer cust = (from c in scope.Extent<Customer>() where c.CustomerID=="ALFKIN" select c).First(); // modify the name in the persistent instance cust.CompanyName = "New Name"; // check if changes should be made persistent // (e.g., whether the OK or Cancel button was pressed) bool doCommit = Check(); if(doCommit) { // the new values of c are stored automatically scope.Transaction.Commit(); } else { // rollback means the changes are not stored in the database scope.Transaction.Rollback(); } |
| VB.NET |
Copy Code |
|
scope.Transaction.Begin()
Dim cust As Customer = (From c In scope.Extent(Of Customer)() _ Where c.CustomerID = "ALFKIN" _ Select c).First()
cust.CompanyName = "New Name"
Dim doCommit As Boolean = Check() If doCommit Then scope.Transaction.Commit() Else scope.Transaction.Rollback() End If |
The rollback operation terminates the transaction without writing any changes to the database. The in-memory objects will be "refreshed" from the database (reloaded with their original data) the next time they are accessed within a subsequent transaction.
If you need the in-memory objects to revert to their original values immediately following a rollback, you can use the transaction property RestoreValues. This might be necessary if you want the objects to have the correct value when used from outside a transaction. The Transaction Properties section discusses this further.
Even if you call Commit(), the transaction may be rolled back if an error is encountered while writing the new or modified objects to the database. This follows from the atomicity property of transactions. An example of a potential error is an index key violation for a unique index. In the example above, if the Customer class has a unique index for the name field and the new name conflicts with a Customer instance already present in the database, the commit will fail with a DuplicateKeyException error. In this case, the entire transaction is rolled back. The transaction may be restarted and the application can take steps to rectify the error.
Closing a Database with Open Transactions
The IObjectScope.Dispose() method throws an exception if the transaction is active. You can check if an IObjectScope instance has an active transaction with the method ITransaction.IsActive(). This example checks if the current transaction is active before disposing of the IObjectScope instance.
| C# |
Copy Code |
|
// determine if the transaction is active or terminated
if ( scope.Transaction.IsActive )
{
scope.Transaction.Rollback();
}
scope.Dispose(); |
| VB.NET |
Copy Code |
|
If scope.Transaction.IsActive Then
scope.Transaction.Rollback() End If scope.Dispose()
|