Changing isolation level within database transaction is ok, including case when you join one transaction to already running one. You just change the way you handle locks from now on. Using Sql Server, this runs without problems:
begin transaction
set transaction isolation level serializable;
select * from FooTable;
set transaction isolation level read committed;
select * from FooTable;
begin transaction
set transaction isolation level serializable;
select * from FooTable;
--transaction_isolation_level can be observed as 4 (serializable)
But, when using .NET TransactionScope to create transaction in said Sql Server like this(C#, xUnit):
[Theory]
[AutoFixtureMagicToGetParameterInstances]
void ZmenaIzolacniUrovneVedeKVyjimce(IFooDao sut, Foo foo)
{
var tranOpts = new TransactionOptions()
{
IsolationLevel = IsolationLevel.Serializable,
Timeout = TimeSpan.FromSeconds(60)
};
var tranOpts2 = new TransactionOptions()
{
IsolationLevel = IsolationLevel.ReadCommitted,
Timeout = TimeSpan.FromSeconds(60)
};
using (var transactionScope = new TransactionScope(TransactionScopeOption.Required, tranOpts))
{
sut.SelectFoos();
using (var transactionScope2 = new TransactionScope(TransactionScopeOption.Required, tranOpts2))
{
sut.SelectFoos();
}
}
}
leads to exception:
System.ArgumentException : The transaction specified for TransactionScope has a different IsolationLevel than the value requested for the scope.
Parameter name: transactionOptions.IsolationLevel
Why designer of TransactionScope deemed it necessary to immediately throw an exception?
I'd expect behavior would be the same at least as long only database resources are involved. Is there something about TransactionScope I'm missing or is it just because reasonable behavior cannot be guaranteed across all possible enlisted resources?