What does DbConnection.EnlistTransaction do?
It allows you to coordinate transactions between multiple connections. A connection will automatically enlist in a transaction if you use TransactionScope. Otherwise you have to do the enlist with an existing transaction.
DbConnection.EnlistTransaction
allows:
- Joining the connection to a
System.Transactions.Transaction
. It has some constraints:- If the connection is already participating in a "local" transaction (
System.Data.Common.DbTransaction
), it may fail with an exception. (This seems to depend on the concrete connection implementation: Firebird 2 does not throw an exception in such situation,SqlConnection
and likely most others do throw.) - If the connection was already joined to another
System.Transactions.Transaction
, and this other transaction is still active, it will fail with an exception.
- If the connection is already participating in a "local" transaction (
- Joining the same transaction repeatedly is supported, at least by
SqlConnection
,OleDbConnection
andOdbcConnection
.
OtherDbConnection
implementations may differ. For instance,HanaConnection
(as of HANA 2 SP3) throws in such case, which is quite inconvenient for code which always explicitly enlists while the connection auto-enlistment has not been disabled in its connection string.
Other providers may also fail to re-enlist in the same transaction if the connection has some resources currently in use, like being used by an opened data reader. (This case looks like a too early check in internal implementation of those connections, done before realizing the supplied transaction is already joined.) - Leaving a transaction in which the connection was enlisted, provided that transaction is no more active. (Otherwise, trying to use the connection may fail with an exception, at least with
OdbcConnection
.) Supplynull
as a transaction for this.
Note that some connections do not support this, likeSqlCeConnection
, which throws aNullReferenceException
, andSQLiteConnection
(at least up to v1.0.105), which throws anArgumentNullException
.
Leaving a transaction after its completion may be required if you want to use the connection for some other operations without joining it in another transaction. Some connections seem to auto-leave the transaction, others seem not.
Connections behavior after scope disposal may also change depending on whether the previous transaction was distributed or not. When distributed, the scope disposal can end as soon as all participants have voted (first phase of the two phases commit), causing the code following the scope disposal to execute concurrently to the second phase, included concurrently to the own second phase of the connection. (See here.) Depending on the connection implementation, explicitly asking for leaving the transaction may alleviate the trouble.
DbConnection.EnlistTransaction
is usually used with System.Transactions.Transaction.Current
. It is not required to use it if the connection is acquired (opened) within a TransactionScope
: in such case, the connection automatically enlists itself in the current transaction (unless its connection string dictates otherwise with enlist=false
). But once again, some connection implementations may differ here too: some do not have auto-enlistment enabled by default and have a quite different semantic for it (like FbConnection prior to its 6.0 version), or do use a different connection string parameter (like MySqlConnection
which uses AutoEnlist
).