Description
It should be possible to control how the DbTransaction is created for generic Database Drivers.
Firebird for example implements its own DbConnection
: FbConnection
.
In this class, there is a Firebird specific overload for the BeginTransaction
Method that lets you use specific Firebird FbTransactionOptions
.
Of course, there is no way for NHibernate to consider such generic implementations.
I have a suggestion for giving the User an optional control over this matter:
Inside AdoTransaction on the Method Begin(IsolationLevel isolationLevel)
there is the following code where the DbTransaction
is created:
if (isolationLevel == IsolationLevel.Unspecified)
{
trans = session.Connection.BeginTransaction();
}
else
{
trans = session.Connection.BeginTransaction(isolationLevel);
}
How about moving that code to a protected virtual Method like this:
protected virtual DbTransaction BeginTransaction(IsolationLevel isolationLevel, ISessionImplementor sessionImplementor)
{
if (isolationLevel == IsolationLevel.Unspecified)
{
return sessionImplementor.Connection.BeginTransaction();
}
else
{
return sessionImplementor.Connection.BeginTransaction(isolationLevel);
}
}
And changing the mentioned code above using that Method:
trans = BeginTransaction(isolationLevel, session);
This way, i can derive from AdoTransaction
and override my own specific implementation.
For example with the specific Firebird Wait
Option:
public class FirebirdAdoTransaction : AdoTransaction
{
public FirebirdAdoTransaction(ISessionImplementor session) : base(session)
{
}
protected override DbTransaction BeginTransaction(IsolationLevel isolationLevel, ISessionImplementor sessionImplementor)
{
if (sessionImplementor.Connection is FbConnection firebird)
{
var transactionOptions = new FbTransactionOptions
{
TransactionBehavior = FbTransactionBehavior.Wait
};
if (isolationLevel == IsolationLevel.ReadCommitted)
{
transactionOptions.TransactionBehavior |= FbTransactionBehavior.ReadCommitted;
}
return firebird.BeginTransaction(transactionOptions);
}
else
{
return base.BeginTransaction(isolationLevel, sessionImplementor);
}
}
}
Then, i only have to create my own TransactionFactory
, using the FirebirdAdoTransaction
and change my NHibernate Settings "transaction.factory_class"
to this Factory:
public class FirebirdTransactionFactory : AdoNetWithSystemTransactionFactory
{
public override ITransaction CreateTransaction(ISessionImplementor session)
{
return new FirebirdAdoTransaction(session);
}
}
I think this is a good addition in general, since you never know what generic implementation of DbConnection
is used by the Database driver and this protected virtual
method gives the user full control over driver related transaction options.
Also: No breaking change.
EDIT:
Changed the name of the protected virtual
method to BeginTransaction
like suggested by hazzik