Skip to content

Allow configuring auto-join transaction globally #2214

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions doc/reference/modules/configuration.xml
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,25 @@ var session = sessions.OpenSession(conn);
</para>
</entry>
</row>
<row>
<entry>
<literal>transaction.auto_join</literal>
</entry>
<entry>
Should sessions check on every operation whether there is an ongoing system transaction or not, and enlist
into it if any?
<para>
Default is <literal>true</literal>. It can also be controlled at session opening, with
<literal>ISessionFactory.WithOptions</literal>. A session can also be instructed to explicitly join the current
transaction by calling <literal>ISession.JoinTransaction</literal>. This setting has no effect when using a
transaction factory that is not system transactions aware.
</para>
<para>
<emphasis role="strong">eg.</emphasis>
<literal>false</literal>
</para>
</entry>
</row>
<row>
<entry>
<literal>default_flush_mode</literal>
Expand Down
6 changes: 4 additions & 2 deletions doc/reference/modules/transactions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -633,9 +633,11 @@ finally
will then fail to use it.
</para>
<para>
As of NHibernate v5.0, session auto-enlistment can be disabled from the session builder
Session auto-enlistment can be controlled from the session builder
obtained with <literal>ISessionFactory.WithOptions()</literal>, using the
<literal>AutoJoinTransaction</literal> option. The connection may still enlist itself
<literal>AutoJoinTransaction</literal> option. It can also be controlled at the configuration level,
see <literal>transaction.auto_join</literal> in <xref linkend="configuration-optional"/>.
When auto-join is disabled, the connection may still enlist itself
if connection string <literal>Enlist</literal> setting is not <literal>false</literal>.
A session can explicitly join the current system transaction by calling
<literal>ISession.JoinTransaction()</literal>.
Expand Down
55 changes: 55 additions & 0 deletions src/NHibernate.Test/SystemTransactions/AutoJoinSettingFixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System.Transactions;
using NHibernate.Cfg;
using NUnit.Framework;

namespace NHibernate.Test.SystemTransactions
{
[TestFixture(true)]
[TestFixture(false)]
[TestFixture(new object[] { null })]
public class AutoJoinSettingFixture : TestCase
{
private readonly bool? _autoJoinTransaction;

public AutoJoinSettingFixture(bool? autoJoinTransaction)
{
_autoJoinTransaction = autoJoinTransaction;
}

protected override string[] Mappings => new[] { "TransactionTest.Person.hbm.xml" };

protected override string MappingsAssembly => "NHibernate.Test";

protected override void Configure(Configuration configuration)
{
if (_autoJoinTransaction.HasValue)
configuration.SetProperty(Environment.AutoJoinTransaction, _autoJoinTransaction.ToString());
else
configuration.Properties.Remove(Environment.AutoJoinTransaction);
}

[Test]
public void CheckTransactionJoined()
{
using (new TransactionScope())
using (var s = OpenSession())
{
Assert.That(
s.GetSessionImplementation().TransactionContext,
_autoJoinTransaction == false ? Is.Null : Is.Not.Null);
}
}

[Theory]
public void CanOverrideAutoJoin(bool autoJoin)
{
using (new TransactionScope())
using (var s = Sfi.WithOptions().AutoJoinTransaction(autoJoin).OpenSession())
{
Assert.That(
s.GetSessionImplementation().TransactionContext,
autoJoin ? Is.Not.Null : Is.Null);
}
}
}
}
12 changes: 12 additions & 0 deletions src/NHibernate/Cfg/Environment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ public static string Version
[Obsolete("This setting has no usages and will be removed in a future version")]
public const string OutputStylesheet = "xml.output_stylesheet";

/// <summary>
/// The class name of a custom <see cref="Transaction.ITransactionFactory"/> implementation. Defaults to the
/// built-in <see cref="Transaction.AdoNetWithSystemTransactionFactory" />.
/// </summary>
public const string TransactionStrategy = "transaction.factory_class";
/// <summary>
/// <para>Timeout duration in milliseconds for the system transaction completion lock.</para>
Expand All @@ -144,6 +148,14 @@ public static string Version
/// transaction preparation, while still benefiting from <see cref="FlushMode.Auto"/> on querying.
/// </summary>
public const string UseConnectionOnSystemTransactionPrepare = "transaction.use_connection_on_system_prepare";
/// <summary>
/// Should sessions check on every operation whether there is an ongoing system transaction or not, and enlist
/// into it if any? Default is <see langword="true"/>. It can also be controlled at session opening, see
/// <see cref="ISessionFactory.WithOptions" />. A session can also be instructed to explicitly join the current
/// transaction by calling <see cref="ISession.JoinTransaction" />. This setting has no effect when using a
/// transaction factory that is not system transactions aware.
/// </summary>
public const string AutoJoinTransaction = "transaction.auto_join";

// Since v5.0.1
[Obsolete("This setting has no usages and will be removed in a future version")]
Expand Down
11 changes: 10 additions & 1 deletion src/NHibernate/Cfg/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ public Settings()

public string SessionFactoryName { get; internal set; }

/// <summary>
/// Should sessions check on every operation whether there is an ongoing system transaction or not, and enlist
/// into it if any? Default is <see langword="true"/>. It can also be controlled at session opening, see
/// <see cref="ISessionFactory.WithOptions" />. A session can also be instructed to explicitly join the current
/// transaction by calling <see cref="ISession.JoinTransaction" />. This setting has no effect if using a
/// transaction factory that is not system transactions aware.
/// </summary>
public bool AutoJoinTransaction { get; internal set; }

public bool IsAutoCreateSchema { get; internal set; }

public bool IsAutoDropSchema { get; internal set; }
Expand Down Expand Up @@ -146,4 +155,4 @@ internal string GetFullCacheRegionName(string name)
return name;
}
}
}
}
1 change: 1 addition & 0 deletions src/NHibernate/Cfg/SettingsFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ public Settings BuildSettings(IDictionary<string, string> properties)
settings.TransactionFactory = transactionFactory;
// Not ported - TransactionManagerLookup
settings.SessionFactoryName = sessionFactoryName;
settings.AutoJoinTransaction = PropertiesHelper.GetBoolean(Environment.AutoJoinTransaction, properties, true);
settings.MaximumFetchDepth = maxFetchDepth;
settings.IsQueryCacheEnabled = useQueryCache;
settings.IsSecondLevelCacheEnabled = useSecondLevelCache;
Expand Down
3 changes: 2 additions & 1 deletion src/NHibernate/ISession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -771,7 +771,8 @@ public partial interface ISession : IDisposable
/// <para>
/// Sessions auto-join current transaction by default on their first usage within a scope.
/// This can be disabled with <see cref="ISessionBuilder{T}.AutoJoinTransaction(bool)"/> from
/// a session builder obtained with <see cref="ISessionFactory.WithOptions()"/>.
/// a session builder obtained with <see cref="ISessionFactory.WithOptions()"/>, or with the
/// auto-join transaction configuration setting.
/// </para>
/// <para>
/// This method allows to explicitly join the current transaction. It does nothing if it is already
Expand Down
3 changes: 2 additions & 1 deletion src/NHibernate/Impl/SessionFactoryImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1415,7 +1415,7 @@ internal class SessionBuilderImpl<T> : ISessionBuilder<T>, ISessionCreationOptio
private ConnectionReleaseMode _connectionReleaseMode;
private FlushMode _flushMode;
private bool _autoClose;
private bool _autoJoinTransaction = true;
private bool _autoJoinTransaction;

public SessionBuilderImpl(SessionFactoryImpl sessionFactory)
{
Expand All @@ -1424,6 +1424,7 @@ public SessionBuilderImpl(SessionFactoryImpl sessionFactory)
// set up default builder values...
_connectionReleaseMode = sessionFactory.Settings.ConnectionReleaseMode;
_autoClose = sessionFactory.Settings.IsAutoCloseSessionEnabled;
_autoJoinTransaction = sessionFactory.Settings.AutoJoinTransaction;
// NH different implementation: not using Settings.IsFlushBeforeCompletionEnabled
_flushMode = sessionFactory.Settings.DefaultFlushMode;
}
Expand Down
20 changes: 19 additions & 1 deletion src/NHibernate/nhibernate-configuration.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,14 @@
<xs:enumeration value="show_sql" />
<xs:enumeration value="max_fetch_depth" />
<xs:enumeration value="current_session_context_class" />
<xs:enumeration value="transaction.factory_class" />
<xs:enumeration value="transaction.factory_class">
<xs:annotation>
<xs:documentation>
The class name of a custom ITransactionFactory implementation.
Defaults to the built-in AdoNetWithSystemTransactionFactory.
</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="cache.provider_class" />
<xs:enumeration value="cache.use_query_cache" />
<xs:enumeration value="cache.query_cache_factory" />
Expand Down Expand Up @@ -174,6 +181,17 @@
</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="transaction.auto_join">
<xs:annotation>
<xs:documentation>
Should sessions check on every operation whether there is an ongoing system transaction or not, and enlist
into it if any? Default is true. It can also be controlled at session opening, with
ISessionFactory.WithOptions. A session can also be instructed to explicitly join the current
transaction by calling ISession.JoinTransaction. This setting has no effect when using a
transaction factory that is not system transactions aware.
</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="oracle.use_n_prefixed_types_for_unicode">
<xs:annotation>
<xs:documentation>
Expand Down