15.02.2015 Views

C# 4 and .NET 4

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

824 ❘ ChaPTer 30 cOre AdO.net<br />

// Close it myself<br />

conn.Close ( );<br />

}<br />

}<br />

catch (SqlException e)<br />

{<br />

// Log the exception<br />

}<br />

Note that this example called Close(), which is not strictly necessary, because the using clause will ensure<br />

that this is done anyway. However, you should ensure that any resources such as this are released as soon<br />

as possible — you might have more code in the rest of the block, <strong>and</strong> there is no point locking a resource<br />

unnecessarily.<br />

In addition, if an exception is raised within the using block, the IDisposable.Dispose method will<br />

be called on the resource guarded by the using clause, which in this example ensures that the database<br />

connection is always closed. This produces easier-to-read code than having to ensure you close a connection<br />

within an exception clause. You might also note that the exception is defined as a SqlException rather<br />

than the catch-all Exception type — always try to catch as specific an exception as possible <strong>and</strong> let all<br />

others that are not explicitly h<strong>and</strong>led rise up the execution stack. You really should only catch this exception<br />

if your specific data class can h<strong>and</strong>le the error <strong>and</strong> do something with it.<br />

In conclusion, if you are writing a class that wraps a resource, whatever that resource may be, always<br />

implement the IDisposable interface to close the resource. That way anyone coding with your class can use<br />

the using() statement <strong>and</strong> guarantee that the resource will be cleared up.<br />

Transactions<br />

Often when there is more than one update to be made to the database, these updates must be performed<br />

within the scope of a transaction. It is common in code to find a transaction object being passed around<br />

to many methods that update the database; however, since the release of the .<strong>NET</strong> Framework 2.0, the<br />

TransactionScope class has been available. This class is found within the System.Transactions<br />

assembly. This vastly simplifies writing transactional code because you can compose several transactional<br />

methods within a transaction scope, <strong>and</strong> the transaction will flow to each of these methods as necessary.<br />

The following sequence of code initiates a transaction on a SQL Server connection:<br />

string source = "server=(local);" +<br />

"integrated security=SSPI;" +<br />

"database=Northwind";<br />

using (TransactionScope scope = new<br />

TransactionScope(TransactionScopeOption.Required))<br />

{<br />

using (SqlConnection conn = new SqlConnection(source))<br />

{<br />

// Do something in SQL<br />

.<br />

}<br />

}<br />

// Then mark complete<br />

scope.Complete();<br />

Here, the transaction is explicitly marked as complete by using the scope.Complete() method. In the<br />

absence of this call, the transaction will be rolled back so that no changes are made to the database.<br />

When you use a transaction scope, you can optionally choose the isolation level for comm<strong>and</strong>s executed<br />

within that transaction. The level determines how changes made in one database session are viewed by<br />

another. Not all database engines support all of the four levels presented in the following table.<br />

www.it-ebooks.info

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!