Printer Friendly Version      Send     
Click to Rate and Give Feedback
Related Articles
Here we explain how the new hierarchyID data type in SQL Server 2008 helps solve some of the problems in modeling and querying hierarchical information.

By Kent Tegels (September 2008)
We introduce you to the benefits of building composite applications with the Composite Application Guidance for WPF from Microsoft patterns & practices.

By Glenn Block (September 2008)
ADO.NET Data Services provide Web-accessible endpoints that allow you to filter, sort, shape, and page data without having to build that functionality yourself.

By Shawn Wildermuth (September 2008)
See how routed events and routed commands in Windows Presentation Foundation form the basis for communication between the parts of your UI.

By Brian Noyes (September 2008)
More ...
Articles by this Author
Here John Papa demonstrates how to build a Silverlight 2 user interface that communicates through WCF to interact with business entities and a database.

By John Papa (September 2008)
Here we build a solution that fits the Entity Framework into an n-tier architecture that uses WCF and WPF and the MVP pattern.

By John Papa (July 2008)
The Entity Framework is a hot topic, but how do you know when to use EntityClient, Object Services, Entity SQL, or LINQ? Find out here.

By John Papa (May 2008)
LINQ to Objects and LINQ to Entities have an arsenal of Standard Query Operators that operate on sequences to perform a wide variety of operations.

By John Papa (March 2008)
With the Entity Framework, developers are given more flexibility by being able to design around a conceptual model rather than a relational data model. To get started, you need to know how to design an Entity Data Model. John Papa walks you through that process.

By John Papa (February 2008)
This month John Papa takes a look at developing a mobile application that can access data on your application server.

By John Papa (January 2008)
WPF is one of the most important new technologies in the .NET Framework 3.0. This month John Papa introduces its data binding capabilities.

By John Papa (December 2007)
In T-SQL, views and derived tables serve similar purposes and have their advantages. But when working with SQL Server 2005,there's a third option--using Common Table Expressions (CTEs). John Papa explains.

By John Papa (October 2007)
More ...
Popular Articles
Animating with Silverlight is easier than you think. Here we create a 3D app that folds a polyhedron using XAML, C#, and by emulating the DirectX math libraries.

By Declan Brennan (April 2008)
Here the author answers questions regarding the Entity Framework and provides an understanding of how and why it was developed.

By Elisa Flasko (July 2008)
In this article we introduce you to BizTalk Services, new technology that offers the Enterprise Service Bus features of BizTalk Server as a hosted service.

By Jon Flanders and Aaron Skonnard (June 2008)
We introduce you to the EDI functionality within BizTalk Server 2006 R2, illustrating schema creation, document mapping, EDI delivery and transmission, and exception handling.

By Mark Beckner (August 2008)
More ...
Read the Blog
SQL Server 2008 supports a new data type, HierarchyID, that helps solve some of the problems in modeling and querying hier­archical information. In the September 2008 issue of MSDN Magazine, Kent Tegels introduces you to the ...
Read more!
Many people using SharePoint technologies don't realize that there is auditing support built directly into the Windows SharePoint Services (WSS) 3.0 platform. In the September 2008 issue of MSDN Magazine, Ted Pattison walks you through a ...
Read more!
The September 2008 issue of MSDN Magazine is now available online. Here's what's in the issue: Hierarchy ID: Model ...
Read more!
Silverlight 2 features a rich and robust control model that is the basis for the controls included in the platform and for third-party control packages. You can also use this control model to build controls of your own. In the August 2008 issue of MSDN Magazine, Jeff Prosise describes how to ...
Read more!
In the August 2008 issue of MSDN Magazine, Matt Milner covers several topics regarding development with Windows Workflow Foundation, some that are intended to address specific reader questions, such as how to safely share a persistence database ...
Read more!
LINQ is a powerful tool enabling quick filtering data based on a standard query language. It can tear through a structured set of data using a simple and straightforward syntax. In the August 2008 issue of MSDN Magazine, Jared Parsons demonstrates a ...
Read more!
More ...
Data Points
ADO.NET and System.Transactions
John Papa

The Microsoft® .NET Framework versions 1.0 and 1.1 represented major changes in software development. However, one important thing that did not change much was support for distributed transactions. All of that is about to change because the .NET Framework 2.0, which includes a new namespace called System.Transactions, will offer significantly improved support for distributed transactions. This new namespace enhances transactional support for managed code and makes it possible to handle transactions without using interception or reflection and without deriving from a ServicedComponent. System.Transactions is also designed to integrate well with the upcoming release of SQL Server 2005 and offers automatic promotion of local lightweight transactions to fully distributed transactions.
In addition, the namespace is flexible enough to handle both implicit (automatic) and explicit (manual) transactions. The implicit transactions require less code, and I find that they cover most of the situations you may encounter. You can even modify some of the settings of the implicit transactions such as the transaction timeout period. Manual transactions are useful when you want to make modifications to a transaction's behavior.
To give you a feel for how this all works, I'll take a look at a code sample that implements an implicit local transaction using the TransactionScope object and its default settings. Then I'll walk through a code sample that modifies the default transactional settings of the implicit local transaction to show you how to modify the isolation level, the timeout period, and a transaction's context. You'll see that the real power is revealed when you design your code for implicit distributed transactions. I will demonstrate how and when the System.Transactions namespace delegates the promotion of a lightweight transaction to a fully distributed transaction and I will explain when more specific control over a transaction is required. Finally, I will walk through an example that shows how to develop explicit transactions and manually choose if and when to enlist in a transaction context. (Don't forget that this column is based on a beta version of the product and details may change.)

Getting Started
The transactional examples I will present will access SQL Server 2000 and SQL Server 2005 databases using ADO.NET and some features of the System.Transactions namespace. Keep in mind that while System.Transactions interacts well with ADO.NET, it is not part of ADO.NET nor the System.Data namespace. This separation allows it to manage transactions across different resource managers including SQL Server, Microsoft Message Queue Server (MSMQ), and Oracle.
The classes I require are in Systems.Transactions.dll, so I need to add a reference to that file from my .NET project in order to take advantage of the managed transactions functionality I'm discussing. You should assume that all of my examples also include the following using statements:
using System.Data;
using System.Data.SqlClient;
using System.Transactions;
Finally, to avoid repeating the connection strings and SQL statements, I have created a few private class fields to store these values (in a real app, these would be properties and would more likely retrieve these values from a configuration file). These fields are shared by all of the methods that I will demonstrate. The first connection string accesses a SQL Server 2005 Beta 2 Northwind database, while the second connects to a SQL Server 2000 Northwind database. There is only a single UPDATE statement that will be executed against both databases, modifying a single row's value in the Customers table. I use it merely to demonstrate the transactions:
private string sCn1 =
  "Server=MyYukonServer;Database=Northwind;Integrated Security=True";
private string sCn2 =
  "Server=MySQL2000Server;Database=Northwind;Integrated Security=True";
private string sSQL = 
  "UPDATE Customers SET City = 'New York' WHERE CustomerID = 'ALFKI'";

Local Implicit Transactions
The first transaction scenario I will walk through is the simplest—a local implicit transaction. This example, shown in Figure 1, shows a connection being made to a single database and a SQL command being executed against it, all wrapped inside of a transaction. There is no distributed transaction required here since only a single database is involved.
The code in Figure 1 begins by creating an instance of the TransactionScope object from the System.Transactions namespace. It creates it within a using statement so that the TransactionScope is guaranteed to be disposed of, even if an exception is thrown in the middle of the code block. The using statement is handy here because it makes sure that the Dispose method is called on the TransactionScope whenever the block is exited. This is important because just before the TransactionScope is disposed, the transaction is completed. When the transaction is complete, the TransactionScope evaluates the Boolean value of the Consistent property (set to false by default). If the value of Consistent is true, the transaction is committed. If the value is false, then the transaction is rolled back. So by employing the using statement, the transaction is guaranteed to make sure the transaction completes, the Consistent flag is checked, and the transaction is committed or rolled back. Note that in the upcoming .NET Framework 2.0 Beta 2, the Consistent flag has been replaced by a new method, Complete, that is to be called on the TransactionScope object when the actions have been performed successfully.
The using keyword does not have to be used, but it is highly recommended. Note that Visual C++® 2005 and Visual Basic® 2005 both support a similar construct, so you should follow the same pattern when using those languages. The important thing here is to make sure that the TransactionScope is disposed, and the using statement just makes it simpler to do that. In addition, the using statement makes it really easy to see everything that is contained within the TransactionScope since it is commonly indented and between the curly braces.
When the SqlConnection.Open method is invoked in Figure 1, the connection is opened and automatically enlists in the current transaction scope. In fact, any connection opened inside of the using statement's curly braces is automatically included in the transaction scope and will participate in the same transaction.
The TransactionScope is smart enough not to create a fully distributed transaction with all of its overhead unless it is necessary. If the resource involved in the transaction is volatile, everything will stay in memory and the Microsoft distributed transaction coordinator (DTC) will not be involved. If the resource is a connection to SQL Server 2005, the DTC will not be involved, and SQL Server 2005 will handle the transaction. This is equivalent to opening an internal SQL transaction. If SQL Server 2000 is used, it will resolve to using a full DTC transaction.
In this example, the TransactionScope will first create a type of transaction called a LightweightTransaction, which is a form of a local, non-distributed transaction. A LightweightTransaction does not use the DTC service and therefore will not show up as a transaction in Component Services transaction statistics (Component Services | Computers | My Computer | Distributed Transaction Coordinator | Transaction Statistics).
To examine this important feature in action, set a breakpoint on the using statement where the TransactionScope is instantiated, then execute the next line by stepping forward once. Then, enter the following command
? System.Transactions.Transaction.Current 
in the Immediate window, which will cause the following output to be generated:
{System.Transactions.Ltm.LightweightTransaction}
    [System.Transactions.Ltm.LightweightTransaction]:
{System.Transactions.Ltm.LightweightTransaction}
    Consistent: false
    Identifier: {a611007b-25fe-4ef5-b92c-5382bbc365be}
    IsolationLevel: System.Transactions.IsolationLevel.Serializable
    Status: System.Transactions.TransactionStatus.Active
    TransactionTraceId: {System.Transactions.TransactionTraceIdentifier}
Notice that from this output you can see that this is a LightweightTransaction object whose Consistent flag is set to false (the default value). The default IsolationLevel is set to Serializable and its Identifier is displayed. The Identifier uniquely identifies the transaction from other transactions. The Status is set to Active because you are currently at a breakpoint in the middle of an active TransactionScope code block. If you examine the properties of the current transaction as it exists immediately after it steps through the line of code that sets the Consistent property, you'll see that the Consistent property's value would change to true.
It's easy to implement transactions using the TransactionScope. If an exception is thrown, the TransactionScope is disposed, the transaction is completed, the Consistent flag is still set to false, and it is rolled back automatically. Just make sure that you do not set the Consistent property to true until you're completely finished with all the actions that should be included in the transaction (in my example, this is just before the closing curly brace of the TransactionScope's using statement).

Transaction Options
You can set the isolation level and the transaction's timeout period on the TransactionScope object by creating a TransactionOptions object. The TransactionOptions class has an IsolationLevel property, which can be used to deviate from the default isolation level of serializable and employ another isolation level such as ReadCommitted. (You should keep in mind that the isolation level is merely a suggestion to the database. Most database engines will try to use the suggested level if possible.) The TransactionOptions class also has a TimeOut property which can be used to deviate from the default of one minute.
Figure 1 used the default TransactionScope object with its default constructor. This sets the isolation level to serializable, the transaction's timeout period to one minute, and its TransactionScopeOptions setting to Required. However, if you want to alter these settings, there are 14 additional overloaded constructors you can use. While the production release of the TransactionScopeOptions enumeration is not yet final, I have listed some of the more familiar values in Figure 2. These settings allow you to control how nested transaction scopes will respond to each other. Figure 3 shows an example of how to take the implicit local transaction from Figure 1 and modify its default settings using these techniques.

Distributed Implicit Transactions
Thus far I have shown how the TransactionScope object can be used to automatically include a single database connection in a transaction scope. Building on this ability by adding a second database connection to the transaction scope is as simple as including the database connection code in the same TransactionScope object's using statement. Figure 4 shows two SQL UPDATE statements being executed against two different databases, both inside of a single transaction scope. The first connection is made to a SQL Server 2005 version of the Northwind database. The second connection is made to a SQL Server 2000 version of Northwind.
You could enhance this code by adding more connections, perhaps to Oracle or even MSMQ, all inside the same transaction scope. Or you could take this further and call a method that performs database actions.
These method calls would also be included in the transaction scope, as long as they are invoked within the transaction scope's using statement. If you called a method and it defined its own TransactionScope, depending on its TransactionScopeOptions setting (see Figure 2), it may join the current transaction scope or even start a new one. This gives you the flexibility to nest distributed transactions against different types of resource managers.

Smart Transactions with SQL Server 2005
Lightweight transactions can be promoted to full, distributed transactions when necessary, without any additional code. When the transaction scope is created, it creates a LightweightTransaction object. When a SQL Server 2005 connection is enlisted in the transaction scope, the transaction remains lightweight and is not under the control of the DTC. If a second connection is made to any database in the same transaction scope, the LightweightTransaction is promoted to a distributed transaction under the domain of the DTC.
SQL Server 2005 has been designed to work well with the System.Transactions features so that it does not use a distributed transaction and all of the overhead that comes along with it unless it requires a distributed transaction. So in the example in Figure 4, when the first connection is created against the SQL Server 2005 database, the transaction stays lightweight. But when it connects to the second database, regardless of the type, the transaction is promoted to a distributed transaction.
You can monitor the transaction being promoted if you step through the code. Step over the first connection that is opened. Then view the transaction statistics of the first database server and you will not see a distributed transaction being created. Next, step over the second connection that is being opened and go back and view the transaction statistics to see that a distributed transaction is now active.
If the first connection in the transaction scope is a SQL Server 2005 database, then the transaction is lightweight but can be delegated for promotion. When the subsequent database connections are opened, the transaction is promoted to a distributed transaction. However, if the first connection is opened against a SQL Server 2000 or Oracle database, note that the transaction won't be promoted because the resource managers for those databases do not support delegated transactions at this time. Therefore when the first connection's database does not support the delegated promotion of transactions, the transaction is created as a full, distributed transaction instead.

Alternatives
You can also create explicit transactions and not use the implicit, automatic transactions. For example, you could manually create a transaction and then tell your connections to explicitly enlist in the transaction scope. The problem with this technique is that it requires more code than the implicit examples and, more importantly, it increases the risk that the transaction will not complete properly if an exception is thrown (you have to manually code the exception handling logic). But just to show how this works, the code in Figure 5 creates a transaction, manually enlists a connection into the transaction, and then commits the transaction.
Regardless of how you implement transactions, it is important to make sure that you get in and out of your transactions quickly. Transactions lock valuable resources. In general, it is a good idea to create a transaction just before you need it, open your connections, execute your action queries, and complete the transaction. You also should avoid running too much non-database code inside the transaction so that other resources aren't locked any longer than it is absolutely necessary.
These transactions also have an effect on connection pooling. When a connection is enlisted in an active transaction scope, even if the connection is closed, it is not fully released to the connection pool to be reused right away. The closed connection is still enlisted in the active transaction scope, so it remains in a special subpool until the active transaction is completed. However, once the transaction is completed, all connections will be released back to their appropriate connection pools.

Conclusion
The System.Transactions namespace can make the management of transactions quick and easy without the need to inherit from a ServicedComponent. One of the greatest features of the LightweightTransaction object is that it can determine if it needs to promote itself to a distributed transaction. The lightweight transactions are also a faster alternative to using the DTC for local transactions. The System.Transactions namespace is a step in the right direction to make it easier to handle transactions.
I want to point out that all of these features were written using the .NET Framework Beta 1 and SQL Server 2005 Beta 2. Therefore, I would expect that some changes to the interfaces or the constructors (the usual suspects) will occur before the final releases of these products. Thus you may need to modify your code once the final products are released.

Send your questions and comments for John to  mmdata@microsoft.com.


John Papa is a baseball fanatic who spends most of his summer nights rooting for the Yankees with his two little girls, wife, and faithful dog, Kadi. He has authored several books on ADO, XML, and SQL Server and can often be found speaking at industry conferences such as VSLive.

© 2008 Microsoft Corporation and CMP Media, LLC. All rights reserved; reproduction in part or in whole without permission is prohibited.
Page view tracker