Skip to content

Commit a264be2

Browse files
maca88hazzik
authored andcommitted
Added the ability to append custom data for a session
1 parent ef0fcf2 commit a264be2

File tree

9 files changed

+140
-14
lines changed

9 files changed

+140
-14
lines changed

src/NHibernate.Test/Async/NHSpecificTest/NH3731/FixtureByCode.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
using NHibernate.Mapping.ByCode;
88
using NUnit.Framework;
99
using System.Threading.Tasks;
10+
using Exception = System.Exception;
11+
using NHibernate.Util;
1012

1113
namespace NHibernate.Test.NHSpecificTest.NH3731
1214
{

src/NHibernate.Test/NHSpecificTest/NH3731/FixtureByCode.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,5 +141,31 @@ public void Serializing_Session_After_Changing_Key_ChildrenMap_Should_Work()
141141
}
142142
}
143143
}
144+
145+
[Test]
146+
public void Deserializing_Session_With_UserData_Should_Work()
147+
{
148+
var context = new Parent { Name = "Parent" };
149+
using (ISession session = sessions.OpenSession(context))
150+
{
151+
ISession deserializedSession;
152+
using (MemoryStream sessionMemoryStream = new MemoryStream())
153+
{
154+
BinaryFormatter formatter = new BinaryFormatter();
155+
formatter.Serialize(sessionMemoryStream, session);
156+
157+
sessionMemoryStream.Seek(0, SeekOrigin.Begin);
158+
deserializedSession = (ISession)formatter.Deserialize(sessionMemoryStream);
159+
}
160+
161+
var deserializedContext = deserializedSession.GetSessionImplementation().UserData as Parent;
162+
Assert.IsNotNull(deserializedContext);
163+
Assert.AreEqual(context.Name, deserializedContext.Name);
164+
Assert.AreNotSame(deserializedContext, context);
165+
166+
deserializedSession.Dispose();
167+
Assert.IsNull(deserializedSession.GetSessionImplementation().UserData);
168+
}
169+
}
144170
}
145171
}

src/NHibernate/Engine/ISessionFactoryImplementor.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,10 @@ public interface ISessionFactoryImplementor : IMapping, ISessionFactory
146146
/// transaction completion?
147147
/// </param>
148148
/// <param name="connectionReleaseMode">The release mode for managed jdbc connections.</param>
149+
/// <param name="userData">The user provided data</param>
149150
/// <returns>An appropriate session.</returns>
150151
ISession OpenSession(DbConnection connection, bool flushBeforeCompletionEnabled, bool autoCloseSessionEnabled,
151-
ConnectionReleaseMode connectionReleaseMode);
152+
ConnectionReleaseMode connectionReleaseMode, object userData = null);
152153

153154
/// <summary>
154155
/// Retrieves a set of all the collection roles in which the given entity

src/NHibernate/Engine/ISessionImplementor.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,5 +337,10 @@ public partial interface ISessionImplementor
337337
EntityKey GenerateEntityKey(object id, IEntityPersister persister);
338338

339339
CacheKey GenerateCacheKey(object id, IType type, string entityOrRoleName);
340+
341+
/// <summary>
342+
/// The user provided data
343+
/// </summary>
344+
object UserData { get; }
340345
}
341346
}

src/NHibernate/ISessionFactory.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,35 @@ public partial interface ISessionFactory : IDisposable
3838
/// </remarks>
3939
ISession OpenSession(DbConnection conn);
4040

41+
/// <summary>
42+
/// Open a <c>ISession</c> on the given connection
43+
/// </summary>
44+
/// <param name="conn">A connection provided by the application</param>
45+
/// <param name="userData">The user provided data</param>
46+
/// <returns>A session</returns>
47+
/// <remarks>
48+
/// Note that the second-level cache will be disabled if you
49+
/// supply a ADO.NET connection. NHibernate will not be able to track
50+
/// any statements you might have executed in the same transaction.
51+
/// Consider implementing your own <see cref="IConnectionProvider" />.
52+
/// </remarks>
53+
ISession OpenSession(DbConnection conn, object userData);
54+
4155
/// <summary>
4256
/// Create database connection and open a <c>ISession</c> on it, specifying an interceptor
4357
/// </summary>
4458
/// <param name="sessionLocalInterceptor">A session-scoped interceptor</param>
4559
/// <returns>A session</returns>
4660
ISession OpenSession(IInterceptor sessionLocalInterceptor);
4761

62+
/// <summary>
63+
/// Create database connection and open a <c>ISession</c> on it, specifying an interceptor
64+
/// </summary>
65+
/// <param name="sessionLocalInterceptor">A session-scoped interceptor</param>
66+
/// <param name="userData">The user provided data</param>
67+
/// <returns>A session</returns>
68+
ISession OpenSession(IInterceptor sessionLocalInterceptor, object userData);
69+
4870
/// <summary>
4971
/// Open a <c>ISession</c> on the given connection, specifying an interceptor
5072
/// </summary>
@@ -59,12 +81,34 @@ public partial interface ISessionFactory : IDisposable
5981
/// </remarks>
6082
ISession OpenSession(DbConnection conn, IInterceptor sessionLocalInterceptor);
6183

84+
/// <summary>
85+
/// Open a <c>ISession</c> on the given connection, specifying an interceptor
86+
/// </summary>
87+
/// <param name="conn">A connection provided by the application</param>
88+
/// <param name="sessionLocalInterceptor">A session-scoped interceptor</param>
89+
/// <param name="userData">The user provided data</param>
90+
/// <returns>A session</returns>
91+
/// <remarks>
92+
/// Note that the second-level cache will be disabled if you
93+
/// supply a ADO.NET connection. NHibernate will not be able to track
94+
/// any statements you might have executed in the same transaction.
95+
/// Consider implementing your own <see cref="IConnectionProvider" />.
96+
/// </remarks>
97+
ISession OpenSession(DbConnection conn, IInterceptor sessionLocalInterceptor, object userData);
98+
6299
/// <summary>
63100
/// Create a database connection and open a <c>ISession</c> on it
64101
/// </summary>
65102
/// <returns></returns>
66103
ISession OpenSession();
67104

105+
/// <summary>
106+
/// Create a database connection and open a <c>ISession</c> on it
107+
/// </summary>
108+
/// <param name="userData">The user provided data</param>
109+
/// <returns>A session</returns>
110+
ISession OpenSession(object userData);
111+
68112
/// <summary>
69113
/// Get the <see cref="IClassMetadata"/> associated with the given entity class
70114
/// </summary>

src/NHibernate/Impl/AbstractSessionImpl.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ public void Initialize()
7272
public abstract object InternalLoad(string entityName, object id, bool eager, bool isNullable);
7373
public abstract object ImmediateLoad(string entityName, object id);
7474
public abstract long Timestamp { get; }
75+
public abstract object UserData { get; }
7576

7677
public EntityKey GenerateEntityKey(object id, IEntityPersister persister)
7778
{

src/NHibernate/Impl/SessionFactoryImpl.cs

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -251,9 +251,9 @@ public SessionFactoryImpl(Configuration cfg, IMapping mapping, Settings settings
251251
if (!allCacheRegions.TryAdd(cache.RegionName, cache.Cache))
252252
{
253253
throw new HibernateException("An item with the same key has already been added to allCacheRegions.");
254-
}
255254
}
256255
}
256+
}
257257
IEntityPersister cp = PersisterFactory.CreateClassPersister(model, cache, this, mapping);
258258
entityPersisters[model.EntityName] = cp;
259259
classMeta[model.EntityName] = cp.ClassMetadata;
@@ -462,15 +462,30 @@ public object GetRealObject(StreamingContext context)
462462

463463
public ISession OpenSession()
464464
{
465-
return OpenSession(interceptor);
465+
return OpenSession(interceptor, null);
466+
}
467+
468+
public ISession OpenSession(object userData)
469+
{
470+
return OpenSession(interceptor, userData);
466471
}
467472

468473
public ISession OpenSession(DbConnection connection)
469474
{
470-
return OpenSession(connection, interceptor);
475+
return OpenSession(connection, interceptor, null);
476+
}
477+
478+
public ISession OpenSession(DbConnection connection, object userData)
479+
{
480+
return OpenSession(connection, interceptor, userData);
471481
}
472482

473483
public ISession OpenSession(DbConnection connection, IInterceptor sessionLocalInterceptor)
484+
{
485+
return OpenSession(connection, sessionLocalInterceptor, null);
486+
}
487+
488+
public ISession OpenSession(DbConnection connection, IInterceptor sessionLocalInterceptor, object userData)
474489
{
475490
if (sessionLocalInterceptor == null)
476491
{
@@ -480,25 +495,31 @@ public ISession OpenSession(DbConnection connection, IInterceptor sessionLocalIn
480495
}
481496

482497
public ISession OpenSession(IInterceptor sessionLocalInterceptor)
498+
{
499+
return OpenSession(sessionLocalInterceptor, null);
500+
}
501+
502+
public ISession OpenSession(IInterceptor sessionLocalInterceptor, object userData)
483503
{
484504
if (sessionLocalInterceptor == null)
485505
{
486506
throw new ArgumentNullException("sessionLocalInterceptor");
487507
}
488508
long timestamp = settings.CacheProvider.NextTimestamp();
489-
return OpenSession(null, true, timestamp, sessionLocalInterceptor);
509+
return OpenSession(null, true, timestamp, sessionLocalInterceptor, userData);
490510
}
491511

492512
public ISession OpenSession(DbConnection connection, bool flushBeforeCompletionEnabled, bool autoCloseSessionEnabled,
493-
ConnectionReleaseMode connectionReleaseMode)
513+
ConnectionReleaseMode connectionReleaseMode, object userData = null)
494514
{
495515
#pragma warning disable 618
496516
var isInterceptorsBeforeTransactionCompletionIgnoreExceptionsEnabled = settings.IsInterceptorsBeforeTransactionCompletionIgnoreExceptionsEnabled;
497517
#pragma warning restore 618
498518

499519
return
500520
new SessionImpl(connection, this, true, settings.CacheProvider.NextTimestamp(), interceptor, flushBeforeCompletionEnabled, autoCloseSessionEnabled,
501-
isInterceptorsBeforeTransactionCompletionIgnoreExceptionsEnabled, connectionReleaseMode, settings.DefaultFlushMode);
521+
isInterceptorsBeforeTransactionCompletionIgnoreExceptionsEnabled, connectionReleaseMode, settings.DefaultFlushMode,
522+
userData);
502523
}
503524

504525
public IEntityPersister GetEntityPersister(string entityName)
@@ -970,7 +991,7 @@ public IDictionary<string, ICache> GetAllSecondLevelCacheRegions()
970991
{
971992
// ToArray creates a moment in time snapshot
972993
return allCacheRegions.ToArray().ToDictionary(kv => kv.Key, kv => kv.Value);
973-
}
994+
}
974995

975996
public ICache GetSecondLevelCacheRegion(string regionName)
976997
{
@@ -1004,12 +1025,12 @@ public IQueryCache GetQueryCache(string cacheRegion)
10041025
return queryCaches.GetOrAdd(
10051026
cacheRegion,
10061027
cr =>
1007-
{
1028+
{
10081029
IQueryCache currentQueryCache = settings.QueryCacheFactory.GetQueryCache(cacheRegion, updateTimestampsCache, settings, properties);
10091030
allCacheRegions[currentQueryCache.RegionName] = currentQueryCache.Cache;
1010-
return currentQueryCache;
1031+
return currentQueryCache;
10111032
});
1012-
}
1033+
}
10131034

10141035
public void EvictQueries()
10151036
{
@@ -1201,15 +1222,15 @@ private IDictionary<string, HibernateException> CheckNamedQueries()
12011222
return errors;
12021223
}
12031224

1204-
private SessionImpl OpenSession(DbConnection connection, bool autoClose, long timestamp, IInterceptor sessionLocalInterceptor)
1225+
private SessionImpl OpenSession(DbConnection connection, bool autoClose, long timestamp, IInterceptor sessionLocalInterceptor, object userData = null)
12051226
{
12061227
#pragma warning disable 618
12071228
var isInterceptorsBeforeTransactionCompletionIgnoreExceptionsEnabled = settings.IsInterceptorsBeforeTransactionCompletionIgnoreExceptionsEnabled;
12081229
#pragma warning restore 618
12091230

12101231
SessionImpl session = new SessionImpl(connection, this, autoClose, timestamp, sessionLocalInterceptor ?? interceptor, settings.IsFlushBeforeCompletionEnabled,
12111232
settings.IsAutoCloseSessionEnabled, isInterceptorsBeforeTransactionCompletionIgnoreExceptionsEnabled,
1212-
settings.ConnectionReleaseMode, settings.DefaultFlushMode);
1233+
settings.ConnectionReleaseMode, settings.DefaultFlushMode, userData);
12131234

12141235
if (sessionLocalInterceptor != null)
12151236
{

src/NHibernate/Impl/SessionImpl.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ public sealed partial class SessionImpl : AbstractSessionImpl, IEventSource, ISe
8686
private readonly bool ignoreExceptionBeforeTransactionCompletion;
8787
[NonSerialized]
8888
private readonly ConnectionReleaseMode connectionReleaseMode;
89+
[NonSerialized]
90+
private object userData;
8991

9092
#region System.Runtime.Serialization.ISerializable Members
9193

@@ -112,6 +114,7 @@ private SessionImpl(SerializationInfo info, StreamingContext context)
112114

113115
flushMode = (FlushMode)info.GetValue("flushMode", typeof(FlushMode));
114116
cacheMode = (CacheMode)info.GetValue("cacheMode", typeof(CacheMode));
117+
userData = info.GetValue("userData", typeof(object));
115118

116119
interceptor = (IInterceptor)info.GetValue("interceptor", typeof(IInterceptor));
117120

@@ -147,6 +150,7 @@ void ISerializable.GetObjectData(SerializationInfo info, StreamingContext contex
147150
info.AddValue("timestamp", timestamp);
148151
info.AddValue("flushMode", flushMode);
149152
info.AddValue("cacheMode", cacheMode);
153+
info.AddValue("userData", userData);
150154

151155
info.AddValue("interceptor", interceptor, typeof(IInterceptor));
152156

@@ -199,6 +203,7 @@ void IDeserializationCallback.OnDeserialization(object sender)
199203
/// <param name="ignoreExceptionBeforeTransactionCompletion">Should we ignore exceptions in IInterceptor.BeforeTransactionCompletion</param>
200204
/// <param name="connectionReleaseMode">The mode by which we should release JDBC connections.</param>
201205
/// <param name="defaultFlushMode">The default flush mode for this session</param>
206+
/// <param name="userData">The user provided data</param>
202207
internal SessionImpl(
203208
DbConnection connection,
204209
SessionFactoryImpl factory,
@@ -209,7 +214,8 @@ internal SessionImpl(
209214
bool autoCloseSessionEnabled,
210215
bool ignoreExceptionBeforeTransactionCompletion,
211216
ConnectionReleaseMode connectionReleaseMode,
212-
FlushMode defaultFlushMode)
217+
FlushMode defaultFlushMode,
218+
object userData = null)
213219
: base(factory)
214220
{
215221
using (new SessionIdLoggingContext(SessionId))
@@ -229,6 +235,7 @@ internal SessionImpl(
229235
this.ignoreExceptionBeforeTransactionCompletion = ignoreExceptionBeforeTransactionCompletion;
230236
connectionManager = new ConnectionManager(this, connection, connectionReleaseMode, interceptor);
231237
this.flushMode = defaultFlushMode;
238+
this.userData = userData;
232239

233240
if (factory.Statistics.IsStatisticsEnabled)
234241
{
@@ -318,6 +325,11 @@ public override long Timestamp
318325
get { return timestamp; }
319326
}
320327

328+
public override object UserData
329+
{
330+
get { return userData; }
331+
}
332+
321333
public ConnectionReleaseMode ConnectionReleaseMode
322334
{
323335
get { return connectionReleaseMode; }
@@ -1679,6 +1691,15 @@ private void Dispose(bool isDisposing)
16791691
}
16801692

16811693
// free unmanaged resources here
1694+
if (userData != null)
1695+
{
1696+
var disposableContext = userData as IDisposable;
1697+
if (disposableContext != null)
1698+
{
1699+
disposableContext.Dispose();
1700+
}
1701+
userData = null;
1702+
}
16821703

16831704
IsAlreadyDisposed = true;
16841705
// nothing for Finalizer to do - so tell the GC to ignore it

src/NHibernate/Impl/StatelessSessionImpl.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ public override long Timestamp
9595
get { throw new NotSupportedException(); }
9696
}
9797

98+
public override object UserData
99+
{
100+
get { throw new NotSupportedException(); }
101+
}
102+
98103
public override IBatcher Batcher
99104
{
100105
get

0 commit comments

Comments
 (0)