I have several code methods that look like this:
using (var connection = this.connectionFactory.GetConnection())
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
using (var command = connection.CreateCommand())
{
command.Transaction = transaction;
command.CommandText = "foo";
command.ExecuteNonQuery();
transaction.Commit();
}
}
}
I now need to call several of these methods together inside an outer transaction, So I did this:
using (var transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
method1();
method2();
method3();
}
but its doing:
The operation is not valid for the state of the transaction.
at System.Transactions.TransactionState.EnlistPromotableSinglePhase(InternalTransaction tx, IPromotableSinglePhaseNotification promotableSinglePhaseNotification, Transaction atomicTransaction)
at System.Transactions.Transaction.EnlistPromotableSinglePhase(IPromotableSinglePhaseNotification promotableSinglePhaseNotification)
at System.Data.SqlClient.SqlInternalConnection.EnlistNonNull(Transaction tx)
at System.Data.SqlClient.SqlInternalConnection.Enlist(Transaction tx)
at System.Data.SqlClient.SqlInternalConnectionTds.Activate(Transaction transaction)
at System.Data.ProviderBase.DbConnectionInternal.ActivateConnection(Transaction transaction)
at System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject)
at System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
at System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, D开发者_高级运维bConnectionFactory connectionFactory)
at System.Data.SqlClient.SqlConnection.Open()
Do I need to replace the IDbTransactions
with TransactionScopes
?
What TransactionScopeOption
should I use for the outer an inner scopes? Im guessing i want RequiresNew
for the outer and Required
for the inners?
The methods will still be called individually (i.e. without an outer TransactionScope
as well as together, so I still need them to be transactionally safe.
Thanks
I believe you are mixing technologies here and should avoid using TransactionScope
and DbTransaction
together because TransactionScope
creates an implicit transaction.
So I would recommend to have your methods similar to:
using (var connection = this.connectionFactory.GetConnection())
{
connection.Open();
using (TransactionScope scope = new TransactionScope())
{
using (var command = connection.CreateCommand())
{
command.CommandText = "foo";
command.ExecuteNonQuery();
}
scope.Complete();
}
}
Then you can call them together:
using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew))
{
method1();
method2();
method3();
scope.Complete();
}
and the methods you called will share the same transaction.
I am not sure of what I will say, but after reading this: http://msdn.microsoft.com/en-us/library/ms172152(v=vs.80).aspx#sectionSection3
I think you should use TransactionScope
in your sub method, but we the option Required
. So when they are called individually, you still have a transaction, and when you call them in the upper method, the transaction sill be integrated in the ambient transaction.
I guess you are doing it right. The inner transaction is enrolled in the same scope of the outer one, and the whole thing will rollback. To have a new transactionscope you have specify "requiresnew".(which u have mentioned) for more clarity refer this post. http://web.archive.org/web/20091012162649/http://www.pluralsight.com/community/blogs/jimjohn/archive/2005/06/18/11451.aspx
精彩评论