Skip to content

Commit 832886d

Browse files
authored
Fix ExecuteWorkInIsolation ignores MultiTenancy configuration (#2835)
1 parent 5748ee0 commit 832886d

File tree

8 files changed

+116
-4
lines changed

8 files changed

+116
-4
lines changed

src/NHibernate.Test/Async/MultiTenancy/DatabaseStrategyNoDbSpecificFixture.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
using NHibernate.Dialect;
2020
using NHibernate.Driver;
2121
using NHibernate.Engine;
22+
using NHibernate.Engine.Transaction;
2223
using NHibernate.Linq;
2324
using NHibernate.Mapping.ByCode;
2425
using NHibernate.MultiTenancy;
@@ -28,6 +29,7 @@
2829
namespace NHibernate.Test.MultiTenancy
2930
{
3031
using System.Threading.Tasks;
32+
using System.Threading;
3133
[TestFixture]
3234
public class DatabaseStrategyNoDbSpecificFixtureAsync : TestCaseMappingByCode
3335
{
@@ -160,6 +162,18 @@ public async Task TenantSessionIsSerializableAndCanBeReconnectedAsync()
160162
Assert.That(Sfi.Statistics.SecondLevelCacheHitCount, Is.EqualTo(1));
161163
}
162164

165+
[Test]
166+
public async Task TenantIsolatedWorkOpensTenantConnectionAsync()
167+
{
168+
if (!IsSqlServerDialect)
169+
Assert.Ignore("MSSqlServer specific test");
170+
171+
using (var ses = OpenTenantSession("tenant1"))
172+
{
173+
await (Isolater.DoIsolatedWorkAsync(new TenantIsolatatedWork("tenant1"), ses.GetSessionImplementation(), CancellationToken.None));
174+
}
175+
}
176+
163177
private static string GetTenantId(ISession session)
164178
{
165179
return session.GetSessionImplementation().GetTenantIdentifier();
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//------------------------------------------------------------------------------
2+
// <auto-generated>
3+
// This code was generated by AsyncGenerator.
4+
//
5+
// Changes to this file may cause incorrect behavior and will be lost if
6+
// the code is regenerated.
7+
// </auto-generated>
8+
//------------------------------------------------------------------------------
9+
10+
11+
using System.Data.Common;
12+
using System.Data.SqlClient;
13+
using NHibernate.Engine.Transaction;
14+
15+
namespace NHibernate.Test.MultiTenancy
16+
{
17+
using System.Threading.Tasks;
18+
using System.Threading;
19+
public partial class TenantIsolatatedWork : IIsolatedWork
20+
{
21+
22+
public Task DoWorkAsync(DbConnection connection, DbTransaction transaction, CancellationToken cancellationToken)
23+
{
24+
var builder = new SqlConnectionStringBuilder(connection.ConnectionString);
25+
if (builder.ApplicationName != _tenantName)
26+
return Task.FromException<object>(new HibernateException("Invalid tenant connection"));
27+
return Task.CompletedTask;
28+
}
29+
}
30+
}

src/NHibernate.Test/MultiTenancy/DatabaseStrategyNoDbSpecificFixture.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using NHibernate.Dialect;
1010
using NHibernate.Driver;
1111
using NHibernate.Engine;
12+
using NHibernate.Engine.Transaction;
1213
using NHibernate.Linq;
1314
using NHibernate.Mapping.ByCode;
1415
using NHibernate.MultiTenancy;
@@ -229,6 +230,18 @@ public void TenantSessionIsSerializableAndCanBeReconnected()
229230
Assert.That(Sfi.Statistics.SecondLevelCacheHitCount, Is.EqualTo(1));
230231
}
231232

233+
[Test]
234+
public void TenantIsolatedWorkOpensTenantConnection()
235+
{
236+
if (!IsSqlServerDialect)
237+
Assert.Ignore("MSSqlServer specific test");
238+
239+
using (var ses = OpenTenantSession("tenant1"))
240+
{
241+
Isolater.DoIsolatedWork(new TenantIsolatatedWork("tenant1"), ses.GetSessionImplementation());
242+
}
243+
}
244+
232245
private static string GetTenantId(ISession session)
233246
{
234247
return session.GetSessionImplementation().GetTenantIdentifier();
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System.Data.Common;
2+
using System.Data.SqlClient;
3+
using NHibernate.Engine.Transaction;
4+
5+
namespace NHibernate.Test.MultiTenancy
6+
{
7+
public partial class TenantIsolatatedWork : IIsolatedWork
8+
{
9+
private readonly string _tenantName;
10+
11+
public TenantIsolatatedWork(string tenantName)
12+
{
13+
_tenantName = tenantName;
14+
}
15+
16+
public void DoWork(DbConnection connection, DbTransaction transaction)
17+
{
18+
var builder = new SqlConnectionStringBuilder(connection.ConnectionString);
19+
if (builder.ApplicationName != _tenantName)
20+
throw new HibernateException("Invalid tenant connection");
21+
}
22+
}
23+
}

src/NHibernate/AdoNet/ConnectionManager.cs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,19 @@ private void CloseConnection()
224224
_connection = null;
225225
}
226226

227+
/// <summary>
228+
/// Get a new opened connection. The caller is responsible for closing it.
229+
/// </summary>
230+
/// <returns>An opened connection.</returns>
231+
public DbConnection GetNewConnection()
232+
{
233+
return _connectionAccess.GetConnection();
234+
}
235+
236+
/// <summary>
237+
/// Get the managed connection.
238+
/// </summary>
239+
/// <returns>An opened connection.</returns>
227240
public DbConnection GetConnection()
228241
{
229242
if (!_allowConnectionUsage)
@@ -254,7 +267,7 @@ public DbConnection GetConnection()
254267
{
255268
if (_ownConnection)
256269
{
257-
_connection = _connectionAccess.GetConnection();
270+
_connection = GetNewConnection();
258271
// Will fail if the connection is already enlisted in another transaction.
259272
// Probable case: nested transaction scope with connection auto-enlistment enabled.
260273
// That is an user error.

src/NHibernate/Async/AdoNet/ConnectionManager.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,25 @@ namespace NHibernate.AdoNet
2525
public partial class ConnectionManager : ISerializable, IDeserializationCallback
2626
{
2727

28+
/// <summary>
29+
/// Get a new opened connection. The caller is responsible for closing it.
30+
/// </summary>
31+
/// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
32+
/// <returns>An opened connection.</returns>
33+
public Task<DbConnection> GetNewConnectionAsync(CancellationToken cancellationToken)
34+
{
35+
if (cancellationToken.IsCancellationRequested)
36+
{
37+
return Task.FromCanceled<DbConnection>(cancellationToken);
38+
}
39+
return _connectionAccess.GetConnectionAsync(cancellationToken);
40+
}
41+
42+
/// <summary>
43+
/// Get the managed connection.
44+
/// </summary>
45+
/// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
46+
/// <returns>An opened connection.</returns>
2847
public Task<DbConnection> GetConnectionAsync(CancellationToken cancellationToken)
2948
{
3049
if (!_allowConnectionUsage)
@@ -62,7 +81,7 @@ async Task<DbConnection> InternalGetConnectionAsync()
6281
{
6382
if (_ownConnection)
6483
{
65-
_connection = await (_connectionAccess.GetConnectionAsync(cancellationToken)).ConfigureAwait(false);
84+
_connection = await (GetNewConnectionAsync(cancellationToken)).ConfigureAwait(false);
6685
// Will fail if the connection is already enlisted in another transaction.
6786
// Probable case: nested transaction scope with connection auto-enlistment enabled.
6887
// That is an user error.

src/NHibernate/Async/Transaction/AdoNetTransactionFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ async Task InternalExecuteWorkInIsolationAsync()
4747
// since SQLite only allows one connection to the database.
4848
connection = session.Factory.Dialect is SQLiteDialect
4949
? session.Connection
50-
: await (session.Factory.ConnectionProvider.GetConnectionAsync(cancellationToken)).ConfigureAwait(false);
50+
: await (session.ConnectionManager.GetNewConnectionAsync(cancellationToken)).ConfigureAwait(false);
5151

5252
if (transacted)
5353
{

src/NHibernate/Transaction/AdoNetTransactionFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public virtual void ExecuteWorkInIsolation(ISessionImplementor session, IIsolate
5757
// since SQLite only allows one connection to the database.
5858
connection = session.Factory.Dialect is SQLiteDialect
5959
? session.Connection
60-
: session.Factory.ConnectionProvider.GetConnection();
60+
: session.ConnectionManager.GetNewConnection();
6161

6262
if (transacted)
6363
{

0 commit comments

Comments
 (0)