Skip to content

Control over BeginTransaction in AdoTransaction #1908

Closed
@greenlight2k

Description

@greenlight2k

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions