Skip to content

Commit 1d8fb9c

Browse files
authored
Add missing ISession.Get(entityName, id, lockMode) (#2378)
1 parent 40a6d0d commit 1d8fb9c

File tree

10 files changed

+300
-125
lines changed

10 files changed

+300
-125
lines changed

src/NHibernate.Test/Async/NHSpecificTest/NH1275/Fixture.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ public async Task RetrievingAsync()
5353
string sql = sqlLogSpy.Appender.GetEvents()[0].RenderedMessage;
5454
Assert.That(sql.IndexOf(Dialect.ForUpdateString, StringComparison.Ordinal), Is.GreaterThan(0));
5555
}
56+
s.Clear();
57+
using (SqlLogSpy sqlLogSpy = new SqlLogSpy())
58+
{
59+
await (s.GetAsync<A>(typeof(A).FullName, savedId, LockMode.Upgrade));
60+
string sql = sqlLogSpy.Appender.GetEvents()[0].RenderedMessage;
61+
Assert.That(sql.IndexOf(Dialect.ForUpdateString, StringComparison.Ordinal), Is.GreaterThan(0));
62+
}
5663
using (SqlLogSpy sqlLogSpy = new SqlLogSpy())
5764
{
5865
await (s.CreateQuery("from A a where a.Id= :pid").SetLockMode("a", LockMode.Upgrade).SetParameter("pid", savedId).

src/NHibernate.Test/NHSpecificTest/NH1275/Fixture.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ public void Retrieving()
4242
string sql = sqlLogSpy.Appender.GetEvents()[0].RenderedMessage;
4343
Assert.That(sql.IndexOf(Dialect.ForUpdateString, StringComparison.Ordinal), Is.GreaterThan(0));
4444
}
45+
s.Clear();
46+
using (SqlLogSpy sqlLogSpy = new SqlLogSpy())
47+
{
48+
s.Get<A>(typeof(A).FullName, savedId, LockMode.Upgrade);
49+
string sql = sqlLogSpy.Appender.GetEvents()[0].RenderedMessage;
50+
Assert.That(sql.IndexOf(Dialect.ForUpdateString, StringComparison.Ordinal), Is.GreaterThan(0));
51+
}
4552
using (SqlLogSpy sqlLogSpy = new SqlLogSpy())
4653
{
4754
s.CreateQuery("from A a where a.Id= :pid").SetLockMode("a", LockMode.Upgrade).SetParameter("pid", savedId).

src/NHibernate/Async/ISession.cs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,76 @@ namespace NHibernate
2626
{
2727
using System.Threading.Tasks;
2828
using System.Threading;
29+
public static partial class SessionExtensions
30+
{
31+
32+
/// <summary>
33+
/// Return the persistent instance of the given entity class with the given identifier, or null
34+
/// if there is no such persistent instance. (If the instance, or a proxy for the instance, is
35+
/// already associated with the session, return that instance or proxy.)
36+
/// </summary>
37+
/// <param name="session">The session.</param>
38+
/// <param name="entityName">The entity name.</param>
39+
/// <param name="id">The entity identifier.</param>
40+
/// <param name="lockMode">The lock mode to use for getting the entity.</param>
41+
/// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
42+
/// <returns>A persistent instance, or <see langword="null" />.</returns>
43+
public static Task<object> GetAsync(this ISession session, string entityName, object id, LockMode lockMode, CancellationToken cancellationToken = default(CancellationToken))
44+
{
45+
if (cancellationToken.IsCancellationRequested)
46+
{
47+
return Task.FromCanceled<object>(cancellationToken);
48+
}
49+
try
50+
{
51+
return
52+
ReflectHelper
53+
.CastOrThrow<SessionImpl>(session, "Get with entityName and lockMode")
54+
.GetAsync(entityName, id, lockMode, cancellationToken);
55+
}
56+
catch (Exception ex)
57+
{
58+
return Task.FromException<object>(ex);
59+
}
60+
}
61+
62+
//NOTE: Keep it as extension
63+
/// <summary>
64+
/// Return the persistent instance of the given entity name with the given identifier, or null
65+
/// if there is no such persistent instance. (If the instance, or a proxy for the instance, is
66+
/// already associated with the session, return that instance or proxy.)
67+
/// </summary>
68+
/// <typeparam name="T">The entity class.</typeparam>
69+
/// <param name="session">The session.</param>
70+
/// <param name="entityName">The entity name.</param>
71+
/// <param name="id">The entity identifier.</param>
72+
/// <param name="lockMode">The lock mode to use for getting the entity.</param>
73+
/// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
74+
/// <returns>A persistent instance, or <see langword="null" />.</returns>
75+
public static async Task<T> GetAsync<T>(this ISession session, string entityName, object id, LockMode lockMode, CancellationToken cancellationToken = default(CancellationToken))
76+
{
77+
cancellationToken.ThrowIfCancellationRequested();
78+
return (T) await (session.GetAsync(entityName, id, lockMode, cancellationToken)).ConfigureAwait(false);
79+
}
80+
81+
//NOTE: Keep it as extension
82+
/// <summary>
83+
/// Return the persistent instance of the given entity name with the given identifier, or null
84+
/// if there is no such persistent instance. (If the instance, or a proxy for the instance, is
85+
/// already associated with the session, return that instance or proxy.)
86+
/// </summary>
87+
/// <typeparam name="T">The entity class.</typeparam>
88+
/// <param name="session">The session.</param>
89+
/// <param name="entityName">The entity name.</param>
90+
/// <param name="id">The entity identifier.</param>
91+
/// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
92+
/// <returns>A persistent instance, or <see langword="null" />.</returns>
93+
public static async Task<T> GetAsync<T>(this ISession session, string entityName, object id, CancellationToken cancellationToken = default(CancellationToken))
94+
{
95+
cancellationToken.ThrowIfCancellationRequested();
96+
return (T) await (session.GetAsync(entityName, id, cancellationToken)).ConfigureAwait(false);
97+
}
98+
}
2999

30100
public partial interface ISession : IDisposable
31101
{

src/NHibernate/Async/IStatelessSession.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,46 @@ namespace NHibernate
2222
{
2323
using System.Threading.Tasks;
2424
using System.Threading;
25+
public static partial class StatelessSessionExtensions
26+
{
27+
28+
//NOTE: Keep it as extension
29+
/// <summary>
30+
/// Return the persistent instance of the given entity name with the given identifier, or null
31+
/// if there is no such persistent instance. (If the instance, or a proxy for the instance, is
32+
/// already associated with the session, return that instance or proxy.)
33+
/// </summary>
34+
/// <typeparam name="T">The entity class.</typeparam>
35+
/// <param name="session">The session.</param>
36+
/// <param name="entityName">The entity name.</param>
37+
/// <param name="id">The entity identifier.</param>
38+
/// <param name="lockMode">The lock mode to use for getting the entity.</param>
39+
/// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
40+
/// <returns>A persistent instance, or <see langword="null" />.</returns>
41+
public static async Task<T> GetAsync<T>(this IStatelessSession session, string entityName, object id, LockMode lockMode, CancellationToken cancellationToken = default(CancellationToken))
42+
{
43+
cancellationToken.ThrowIfCancellationRequested();
44+
return (T) await (session.GetAsync(entityName, id, lockMode, cancellationToken)).ConfigureAwait(false);
45+
}
46+
47+
//NOTE: Keep it as extension
48+
/// <summary>
49+
/// Return the persistent instance of the given entity name with the given identifier, or null
50+
/// if there is no such persistent instance. (If the instance, or a proxy for the instance, is
51+
/// already associated with the session, return that instance or proxy.)
52+
/// </summary>
53+
/// <typeparam name="T">The entity class.</typeparam>
54+
/// <param name="session">The session.</param>
55+
/// <param name="entityName">The entity name.</param>
56+
/// <param name="id">The entity identifier.</param>
57+
/// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
58+
/// <returns>A persistent instance, or <see langword="null" />.</returns>
59+
public static async Task<T> GetAsync<T>(this IStatelessSession session, string entityName, object id, CancellationToken cancellationToken = default(CancellationToken))
60+
{
61+
cancellationToken.ThrowIfCancellationRequested();
62+
return (T) await (session.GetAsync(entityName, id, cancellationToken)).ConfigureAwait(false);
63+
}
64+
}
2565

2666
public partial interface IStatelessSession : IDisposable
2767
{

src/NHibernate/Async/Impl/SessionImpl.cs

Lines changed: 40 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -803,24 +803,21 @@ public override async Task<bool> AutoFlushIfRequiredAsync(ISet<string> querySpac
803803
return LoadAsync(entityClass.FullName, id, cancellationToken);
804804
}
805805

806+
/// <inheritdoc />
806807
public async Task<T> GetAsync<T>(object id, CancellationToken cancellationToken = default(CancellationToken))
807808
{
808809
cancellationToken.ThrowIfCancellationRequested();
809-
using (BeginProcess())
810-
{
811-
return (T)await (GetAsync(typeof(T), id, cancellationToken)).ConfigureAwait(false);
812-
}
810+
return (T) await (GetAsync(typeof(T), id, cancellationToken)).ConfigureAwait(false);
813811
}
814812

813+
/// <inheritdoc />
815814
public async Task<T> GetAsync<T>(object id, LockMode lockMode, CancellationToken cancellationToken = default(CancellationToken))
816815
{
817816
cancellationToken.ThrowIfCancellationRequested();
818-
using (BeginProcess())
819-
{
820-
return (T)await (GetAsync(typeof(T), id, lockMode, cancellationToken)).ConfigureAwait(false);
821-
}
817+
return (T) await (GetAsync(typeof(T), id, lockMode, cancellationToken)).ConfigureAwait(false);
822818
}
823819

820+
/// <inheritdoc />
824821
public Task<object> GetAsync(System.Type entityClass, object id, CancellationToken cancellationToken = default(CancellationToken))
825822
{
826823
if (cancellationToken.IsCancellationRequested)
@@ -830,29 +827,50 @@ public override async Task<bool> AutoFlushIfRequiredAsync(ISet<string> querySpac
830827
return GetAsync(entityClass.FullName, id, cancellationToken);
831828
}
832829

833-
/// <summary>
834-
/// Load the data for the object with the specified id into a newly created object
835-
/// using "for update", if supported. A new key will be assigned to the object.
836-
/// This should return an existing proxy where appropriate.
837-
///
838-
/// If the object does not exist in the database, null is returned.
839-
/// </summary>
840-
/// <param name="clazz"></param>
841-
/// <param name="id"></param>
842-
/// <param name="lockMode"></param>
843-
/// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
844-
/// <returns></returns>
845-
public async Task<object> GetAsync(System.Type clazz, object id, LockMode lockMode, CancellationToken cancellationToken = default(CancellationToken))
830+
/// <inheritdoc />
831+
public Task<object> GetAsync(System.Type clazz, object id, LockMode lockMode, CancellationToken cancellationToken = default(CancellationToken))
832+
{
833+
if (cancellationToken.IsCancellationRequested)
834+
{
835+
return Task.FromCanceled<object>(cancellationToken);
836+
}
837+
return GetAsync(clazz.FullName, id, lockMode, cancellationToken);
838+
}
839+
840+
/// <inheritdoc />
841+
public async Task<object> GetAsync(string entityName, object id, LockMode lockMode, CancellationToken cancellationToken)
846842
{
847843
cancellationToken.ThrowIfCancellationRequested();
848844
using (BeginProcess())
849845
{
850-
LoadEvent loadEvent = new LoadEvent(id, clazz.FullName, lockMode, this);
846+
LoadEvent loadEvent = new LoadEvent(id, entityName, lockMode, this);
851847
await (FireLoadAsync(loadEvent, LoadEventListener.Get, cancellationToken)).ConfigureAwait(false);
848+
//Note: AfterOperation call is skipped to avoid releasing the lock when outside of a transaction.
852849
return loadEvent.Result;
853850
}
854851
}
855852

853+
/// <inheritdoc />
854+
public async Task<object> GetAsync(string entityName, object id, CancellationToken cancellationToken = default(CancellationToken))
855+
{
856+
cancellationToken.ThrowIfCancellationRequested();
857+
using (BeginProcess())
858+
{
859+
LoadEvent loadEvent = new LoadEvent(id, entityName, null, this);
860+
bool success = false;
861+
try
862+
{
863+
await (FireLoadAsync(loadEvent, LoadEventListener.Get, cancellationToken)).ConfigureAwait(false);
864+
success = true;
865+
return loadEvent.Result;
866+
}
867+
finally
868+
{
869+
await (AfterOperationAsync(success, cancellationToken)).ConfigureAwait(false);
870+
}
871+
}
872+
}
873+
856874
public async Task<string> GetEntityNameAsync(object obj, CancellationToken cancellationToken = default(CancellationToken))
857875
{
858876
cancellationToken.ThrowIfCancellationRequested();
@@ -882,26 +900,6 @@ public override async Task<bool> AutoFlushIfRequiredAsync(ISet<string> querySpac
882900
}
883901
}
884902

885-
public async Task<object> GetAsync(string entityName, object id, CancellationToken cancellationToken = default(CancellationToken))
886-
{
887-
cancellationToken.ThrowIfCancellationRequested();
888-
using (BeginProcess())
889-
{
890-
LoadEvent loadEvent = new LoadEvent(id, entityName, false, this);
891-
bool success = false;
892-
try
893-
{
894-
await (FireLoadAsync(loadEvent, LoadEventListener.Get, cancellationToken)).ConfigureAwait(false);
895-
success = true;
896-
return loadEvent.Result;
897-
}
898-
finally
899-
{
900-
await (AfterOperationAsync(success, cancellationToken)).ConfigureAwait(false);
901-
}
902-
}
903-
}
904-
905903
/// <summary>
906904
/// Load the data for the object with the specified id into a newly created object.
907905
/// This is only called when lazily initializing a proxy.

src/NHibernate/Async/Impl/StatelessSessionImpl.cs

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ public async Task ManagedFlushAsync(CancellationToken cancellationToken)
439439
}
440440
}
441441

442-
/// <summary> Retrieve a entity. </summary>
442+
/// <summary> Retrieve an entity. </summary>
443443
/// <returns> a detached entity instance </returns>
444444
public Task<object> GetAsync(string entityName, object id, CancellationToken cancellationToken = default(CancellationToken))
445445
{
@@ -450,39 +450,27 @@ public async Task ManagedFlushAsync(CancellationToken cancellationToken)
450450
return GetAsync(entityName, id, LockMode.None, cancellationToken);
451451
}
452452

453-
/// <summary> Retrieve a entity.
454-
///
453+
/// <summary>
454+
/// Retrieve an entity.
455455
/// </summary>
456456
/// <returns> a detached entity instance
457457
/// </returns>
458458
public async Task<T> GetAsync<T>(object id, CancellationToken cancellationToken = default(CancellationToken))
459459
{
460460
cancellationToken.ThrowIfCancellationRequested();
461-
using (BeginProcess())
462-
{
463-
return (T)await (GetAsync(typeof(T), id, cancellationToken)).ConfigureAwait(false);
464-
}
465-
}
466-
467-
private Task<object> GetAsync(System.Type persistentClass, object id, CancellationToken cancellationToken)
468-
{
469-
if (cancellationToken.IsCancellationRequested)
470-
{
471-
return Task.FromCanceled<object>(cancellationToken);
472-
}
473-
return GetAsync(persistentClass.FullName, id, cancellationToken);
461+
return (T) await (GetAsync(typeof(T).FullName, id, cancellationToken)).ConfigureAwait(false);
474462
}
475463

476464
/// <summary>
477-
/// Retrieve a entity, obtaining the specified lock mode.
465+
/// Retrieve an entity, obtaining the specified lock mode.
478466
/// </summary>
479467
/// <returns> a detached entity instance </returns>
480468
public async Task<object> GetAsync(string entityName, object id, LockMode lockMode, CancellationToken cancellationToken = default(CancellationToken))
481469
{
482470
cancellationToken.ThrowIfCancellationRequested();
483471
using (BeginProcess())
484472
{
485-
object result = await (Factory.GetEntityPersister(entityName).LoadAsync(id, null, lockMode, this, cancellationToken)).ConfigureAwait(false);
473+
object result = await (Factory.GetEntityPersister(entityName).LoadAsync(id, null, lockMode ?? LockMode.None, this, cancellationToken)).ConfigureAwait(false);
486474
if (temporaryPersistenceContext.IsLoadFinished)
487475
{
488476
temporaryPersistenceContext.Clear();
@@ -492,16 +480,13 @@ private Task<object> GetAsync(System.Type persistentClass, object id, Cancellati
492480
}
493481

494482
/// <summary>
495-
/// Retrieve a entity, obtaining the specified lock mode.
483+
/// Retrieve an entity, obtaining the specified lock mode.
496484
/// </summary>
497485
/// <returns> a detached entity instance </returns>
498486
public async Task<T> GetAsync<T>(object id, LockMode lockMode, CancellationToken cancellationToken = default(CancellationToken))
499487
{
500488
cancellationToken.ThrowIfCancellationRequested();
501-
using (BeginProcess())
502-
{
503-
return (T)await (GetAsync(typeof(T).FullName, id, lockMode, cancellationToken)).ConfigureAwait(false);
504-
}
489+
return (T) await (GetAsync(typeof(T).FullName, id, lockMode, cancellationToken)).ConfigureAwait(false);
505490
}
506491

507492
/// <summary>

0 commit comments

Comments
 (0)