diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1275/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1275/Fixture.cs index 57ecaea5761..5503e4bb9db 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1275/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1275/Fixture.cs @@ -53,6 +53,13 @@ public async Task RetrievingAsync() string sql = sqlLogSpy.Appender.GetEvents()[0].RenderedMessage; Assert.That(sql.IndexOf(Dialect.ForUpdateString, StringComparison.Ordinal), Is.GreaterThan(0)); } + s.Clear(); + using (SqlLogSpy sqlLogSpy = new SqlLogSpy()) + { + await (s.GetAsync(typeof(A).FullName, savedId, LockMode.Upgrade)); + string sql = sqlLogSpy.Appender.GetEvents()[0].RenderedMessage; + Assert.That(sql.IndexOf(Dialect.ForUpdateString, StringComparison.Ordinal), Is.GreaterThan(0)); + } using (SqlLogSpy sqlLogSpy = new SqlLogSpy()) { await (s.CreateQuery("from A a where a.Id= :pid").SetLockMode("a", LockMode.Upgrade).SetParameter("pid", savedId). diff --git a/src/NHibernate.Test/NHSpecificTest/NH1275/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1275/Fixture.cs index 350b40f4dc9..4318dc5839f 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1275/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1275/Fixture.cs @@ -42,6 +42,13 @@ public void Retrieving() string sql = sqlLogSpy.Appender.GetEvents()[0].RenderedMessage; Assert.That(sql.IndexOf(Dialect.ForUpdateString, StringComparison.Ordinal), Is.GreaterThan(0)); } + s.Clear(); + using (SqlLogSpy sqlLogSpy = new SqlLogSpy()) + { + s.Get(typeof(A).FullName, savedId, LockMode.Upgrade); + string sql = sqlLogSpy.Appender.GetEvents()[0].RenderedMessage; + Assert.That(sql.IndexOf(Dialect.ForUpdateString, StringComparison.Ordinal), Is.GreaterThan(0)); + } using (SqlLogSpy sqlLogSpy = new SqlLogSpy()) { s.CreateQuery("from A a where a.Id= :pid").SetLockMode("a", LockMode.Upgrade).SetParameter("pid", savedId). diff --git a/src/NHibernate/Async/ISession.cs b/src/NHibernate/Async/ISession.cs index fbe6f6d19a6..71cf958c903 100644 --- a/src/NHibernate/Async/ISession.cs +++ b/src/NHibernate/Async/ISession.cs @@ -26,6 +26,76 @@ namespace NHibernate { using System.Threading.Tasks; using System.Threading; + public static partial class SessionExtensions + { + + /// + /// Return the persistent instance of the given entity class with the given identifier, or null + /// if there is no such persistent instance. (If the instance, or a proxy for the instance, is + /// already associated with the session, return that instance or proxy.) + /// + /// The session. + /// The entity name. + /// The entity identifier. + /// The lock mode to use for getting the entity. + /// A cancellation token that can be used to cancel the work + /// A persistent instance, or . + public static Task GetAsync(this ISession session, string entityName, object id, LockMode lockMode, CancellationToken cancellationToken = default(CancellationToken)) + { + if (cancellationToken.IsCancellationRequested) + { + return Task.FromCanceled(cancellationToken); + } + try + { + return + ReflectHelper + .CastOrThrow(session, "Get with entityName and lockMode") + .GetAsync(entityName, id, lockMode, cancellationToken); + } + catch (Exception ex) + { + return Task.FromException(ex); + } + } + + //NOTE: Keep it as extension + /// + /// Return the persistent instance of the given entity name with the given identifier, or null + /// if there is no such persistent instance. (If the instance, or a proxy for the instance, is + /// already associated with the session, return that instance or proxy.) + /// + /// The entity class. + /// The session. + /// The entity name. + /// The entity identifier. + /// The lock mode to use for getting the entity. + /// A cancellation token that can be used to cancel the work + /// A persistent instance, or . + public static async Task GetAsync(this ISession session, string entityName, object id, LockMode lockMode, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + return (T) await (session.GetAsync(entityName, id, lockMode, cancellationToken)).ConfigureAwait(false); + } + + //NOTE: Keep it as extension + /// + /// Return the persistent instance of the given entity name with the given identifier, or null + /// if there is no such persistent instance. (If the instance, or a proxy for the instance, is + /// already associated with the session, return that instance or proxy.) + /// + /// The entity class. + /// The session. + /// The entity name. + /// The entity identifier. + /// A cancellation token that can be used to cancel the work + /// A persistent instance, or . + public static async Task GetAsync(this ISession session, string entityName, object id, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + return (T) await (session.GetAsync(entityName, id, cancellationToken)).ConfigureAwait(false); + } + } public partial interface ISession : IDisposable { diff --git a/src/NHibernate/Async/IStatelessSession.cs b/src/NHibernate/Async/IStatelessSession.cs index 5e86ca768c8..040f5b92e7c 100644 --- a/src/NHibernate/Async/IStatelessSession.cs +++ b/src/NHibernate/Async/IStatelessSession.cs @@ -22,6 +22,46 @@ namespace NHibernate { using System.Threading.Tasks; using System.Threading; + public static partial class StatelessSessionExtensions + { + + //NOTE: Keep it as extension + /// + /// Return the persistent instance of the given entity name with the given identifier, or null + /// if there is no such persistent instance. (If the instance, or a proxy for the instance, is + /// already associated with the session, return that instance or proxy.) + /// + /// The entity class. + /// The session. + /// The entity name. + /// The entity identifier. + /// The lock mode to use for getting the entity. + /// A cancellation token that can be used to cancel the work + /// A persistent instance, or . + public static async Task GetAsync(this IStatelessSession session, string entityName, object id, LockMode lockMode, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + return (T) await (session.GetAsync(entityName, id, lockMode, cancellationToken)).ConfigureAwait(false); + } + + //NOTE: Keep it as extension + /// + /// Return the persistent instance of the given entity name with the given identifier, or null + /// if there is no such persistent instance. (If the instance, or a proxy for the instance, is + /// already associated with the session, return that instance or proxy.) + /// + /// The entity class. + /// The session. + /// The entity name. + /// The entity identifier. + /// A cancellation token that can be used to cancel the work + /// A persistent instance, or . + public static async Task GetAsync(this IStatelessSession session, string entityName, object id, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + return (T) await (session.GetAsync(entityName, id, cancellationToken)).ConfigureAwait(false); + } + } public partial interface IStatelessSession : IDisposable { diff --git a/src/NHibernate/Async/Impl/SessionImpl.cs b/src/NHibernate/Async/Impl/SessionImpl.cs index 8335e43d62f..03d89beaa52 100644 --- a/src/NHibernate/Async/Impl/SessionImpl.cs +++ b/src/NHibernate/Async/Impl/SessionImpl.cs @@ -803,24 +803,21 @@ public override async Task AutoFlushIfRequiredAsync(ISet querySpac return LoadAsync(entityClass.FullName, id, cancellationToken); } + /// public async Task GetAsync(object id, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); - using (BeginProcess()) - { - return (T)await (GetAsync(typeof(T), id, cancellationToken)).ConfigureAwait(false); - } + return (T) await (GetAsync(typeof(T), id, cancellationToken)).ConfigureAwait(false); } + /// public async Task GetAsync(object id, LockMode lockMode, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); - using (BeginProcess()) - { - return (T)await (GetAsync(typeof(T), id, lockMode, cancellationToken)).ConfigureAwait(false); - } + return (T) await (GetAsync(typeof(T), id, lockMode, cancellationToken)).ConfigureAwait(false); } + /// public Task GetAsync(System.Type entityClass, object id, CancellationToken cancellationToken = default(CancellationToken)) { if (cancellationToken.IsCancellationRequested) @@ -830,29 +827,50 @@ public override async Task AutoFlushIfRequiredAsync(ISet querySpac return GetAsync(entityClass.FullName, id, cancellationToken); } - /// - /// Load the data for the object with the specified id into a newly created object - /// using "for update", if supported. A new key will be assigned to the object. - /// This should return an existing proxy where appropriate. - /// - /// If the object does not exist in the database, null is returned. - /// - /// - /// - /// - /// A cancellation token that can be used to cancel the work - /// - public async Task GetAsync(System.Type clazz, object id, LockMode lockMode, CancellationToken cancellationToken = default(CancellationToken)) + /// + public Task GetAsync(System.Type clazz, object id, LockMode lockMode, CancellationToken cancellationToken = default(CancellationToken)) + { + if (cancellationToken.IsCancellationRequested) + { + return Task.FromCanceled(cancellationToken); + } + return GetAsync(clazz.FullName, id, lockMode, cancellationToken); + } + + /// + public async Task GetAsync(string entityName, object id, LockMode lockMode, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); using (BeginProcess()) { - LoadEvent loadEvent = new LoadEvent(id, clazz.FullName, lockMode, this); + LoadEvent loadEvent = new LoadEvent(id, entityName, lockMode, this); await (FireLoadAsync(loadEvent, LoadEventListener.Get, cancellationToken)).ConfigureAwait(false); + //Note: AfterOperation call is skipped to avoid releasing the lock when outside of a transaction. return loadEvent.Result; } } + /// + public async Task GetAsync(string entityName, object id, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + using (BeginProcess()) + { + LoadEvent loadEvent = new LoadEvent(id, entityName, null, this); + bool success = false; + try + { + await (FireLoadAsync(loadEvent, LoadEventListener.Get, cancellationToken)).ConfigureAwait(false); + success = true; + return loadEvent.Result; + } + finally + { + await (AfterOperationAsync(success, cancellationToken)).ConfigureAwait(false); + } + } + } + public async Task GetEntityNameAsync(object obj, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); @@ -882,26 +900,6 @@ public override async Task AutoFlushIfRequiredAsync(ISet querySpac } } - public async Task GetAsync(string entityName, object id, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - using (BeginProcess()) - { - LoadEvent loadEvent = new LoadEvent(id, entityName, false, this); - bool success = false; - try - { - await (FireLoadAsync(loadEvent, LoadEventListener.Get, cancellationToken)).ConfigureAwait(false); - success = true; - return loadEvent.Result; - } - finally - { - await (AfterOperationAsync(success, cancellationToken)).ConfigureAwait(false); - } - } - } - /// /// Load the data for the object with the specified id into a newly created object. /// This is only called when lazily initializing a proxy. diff --git a/src/NHibernate/Async/Impl/StatelessSessionImpl.cs b/src/NHibernate/Async/Impl/StatelessSessionImpl.cs index 317f731c37a..162baafddc2 100644 --- a/src/NHibernate/Async/Impl/StatelessSessionImpl.cs +++ b/src/NHibernate/Async/Impl/StatelessSessionImpl.cs @@ -439,7 +439,7 @@ public async Task ManagedFlushAsync(CancellationToken cancellationToken) } } - /// Retrieve a entity. + /// Retrieve an entity. /// a detached entity instance public Task GetAsync(string entityName, object id, CancellationToken cancellationToken = default(CancellationToken)) { @@ -450,31 +450,19 @@ public async Task ManagedFlushAsync(CancellationToken cancellationToken) return GetAsync(entityName, id, LockMode.None, cancellationToken); } - /// Retrieve a entity. - /// + /// + /// Retrieve an entity. /// /// a detached entity instance /// public async Task GetAsync(object id, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); - using (BeginProcess()) - { - return (T)await (GetAsync(typeof(T), id, cancellationToken)).ConfigureAwait(false); - } - } - - private Task GetAsync(System.Type persistentClass, object id, CancellationToken cancellationToken) - { - if (cancellationToken.IsCancellationRequested) - { - return Task.FromCanceled(cancellationToken); - } - return GetAsync(persistentClass.FullName, id, cancellationToken); + return (T) await (GetAsync(typeof(T).FullName, id, cancellationToken)).ConfigureAwait(false); } /// - /// Retrieve a entity, obtaining the specified lock mode. + /// Retrieve an entity, obtaining the specified lock mode. /// /// a detached entity instance public async Task GetAsync(string entityName, object id, LockMode lockMode, CancellationToken cancellationToken = default(CancellationToken)) @@ -482,7 +470,7 @@ private Task GetAsync(System.Type persistentClass, object id, Cancellati cancellationToken.ThrowIfCancellationRequested(); using (BeginProcess()) { - object result = await (Factory.GetEntityPersister(entityName).LoadAsync(id, null, lockMode, this, cancellationToken)).ConfigureAwait(false); + object result = await (Factory.GetEntityPersister(entityName).LoadAsync(id, null, lockMode ?? LockMode.None, this, cancellationToken)).ConfigureAwait(false); if (temporaryPersistenceContext.IsLoadFinished) { temporaryPersistenceContext.Clear(); @@ -492,16 +480,13 @@ private Task GetAsync(System.Type persistentClass, object id, Cancellati } /// - /// Retrieve a entity, obtaining the specified lock mode. + /// Retrieve an entity, obtaining the specified lock mode. /// /// a detached entity instance public async Task GetAsync(object id, LockMode lockMode, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); - using (BeginProcess()) - { - return (T)await (GetAsync(typeof(T).FullName, id, lockMode, cancellationToken)).ConfigureAwait(false); - } + return (T) await (GetAsync(typeof(T).FullName, id, lockMode, cancellationToken)).ConfigureAwait(false); } /// diff --git a/src/NHibernate/ISession.cs b/src/NHibernate/ISession.cs index 99a8ba12a56..237dc9823c0 100644 --- a/src/NHibernate/ISession.cs +++ b/src/NHibernate/ISession.cs @@ -15,7 +15,7 @@ namespace NHibernate { // 6.0 TODO: Convert most of these extensions to interface methods - public static class SessionExtensions + public static partial class SessionExtensions { /// /// Obtain a builder with the ability to grab certain information from @@ -48,6 +48,57 @@ public static IQueryBatch CreateQueryBatch(this ISession session) /// The current transaction or .. public static ITransaction GetCurrentTransaction(this ISession session) => session.GetSessionImplementation().ConnectionManager.CurrentTransaction; + + /// + /// Return the persistent instance of the given entity class with the given identifier, or null + /// if there is no such persistent instance. (If the instance, or a proxy for the instance, is + /// already associated with the session, return that instance or proxy.) + /// + /// The session. + /// The entity name. + /// The entity identifier. + /// The lock mode to use for getting the entity. + /// A persistent instance, or . + public static object Get(this ISession session, string entityName, object id, LockMode lockMode) + { + return + ReflectHelper + .CastOrThrow(session, "Get with entityName and lockMode") + .Get(entityName, id, lockMode); + } + + //NOTE: Keep it as extension + /// + /// Return the persistent instance of the given entity name with the given identifier, or null + /// if there is no such persistent instance. (If the instance, or a proxy for the instance, is + /// already associated with the session, return that instance or proxy.) + /// + /// The entity class. + /// The session. + /// The entity name. + /// The entity identifier. + /// The lock mode to use for getting the entity. + /// A persistent instance, or . + public static T Get(this ISession session, string entityName, object id, LockMode lockMode) + { + return (T) session.Get(entityName, id, lockMode); + } + + //NOTE: Keep it as extension + /// + /// Return the persistent instance of the given entity name with the given identifier, or null + /// if there is no such persistent instance. (If the instance, or a proxy for the instance, is + /// already associated with the session, return that instance or proxy.) + /// + /// The entity class. + /// The session. + /// The entity name. + /// The entity identifier. + /// A persistent instance, or . + public static T Get(this ISession session, string entityName, object id) + { + return (T) session.Get(entityName, id); + } } /// diff --git a/src/NHibernate/IStatelessSession.cs b/src/NHibernate/IStatelessSession.cs index df8fcce4063..483caec8224 100644 --- a/src/NHibernate/IStatelessSession.cs +++ b/src/NHibernate/IStatelessSession.cs @@ -11,7 +11,7 @@ namespace NHibernate { // 6.0 TODO: Convert most of these extensions to interface methods - public static class StatelessSessionExtensions + public static partial class StatelessSessionExtensions { /// /// Creates a for the session. @@ -31,6 +31,39 @@ public static IQueryBatch CreateQueryBatch(this IStatelessSession session) /// The current transaction or .. public static ITransaction GetCurrentTransaction(this IStatelessSession session) => session.GetSessionImplementation().ConnectionManager.CurrentTransaction; + + //NOTE: Keep it as extension + /// + /// Return the persistent instance of the given entity name with the given identifier, or null + /// if there is no such persistent instance. (If the instance, or a proxy for the instance, is + /// already associated with the session, return that instance or proxy.) + /// + /// The entity class. + /// The session. + /// The entity name. + /// The entity identifier. + /// The lock mode to use for getting the entity. + /// A persistent instance, or . + public static T Get(this IStatelessSession session, string entityName, object id, LockMode lockMode) + { + return (T) session.Get(entityName, id, lockMode); + } + + //NOTE: Keep it as extension + /// + /// Return the persistent instance of the given entity name with the given identifier, or null + /// if there is no such persistent instance. (If the instance, or a proxy for the instance, is + /// already associated with the session, return that instance or proxy.) + /// + /// The entity class. + /// The session. + /// The entity name. + /// The entity identifier. + /// A persistent instance, or . + public static T Get(this IStatelessSession session, string entityName, object id) + { + return (T) session.Get(entityName, id); + } } /// diff --git a/src/NHibernate/Impl/SessionImpl.cs b/src/NHibernate/Impl/SessionImpl.cs index b690cd8d637..341a8df46aa 100644 --- a/src/NHibernate/Impl/SessionImpl.cs +++ b/src/NHibernate/Impl/SessionImpl.cs @@ -1156,48 +1156,62 @@ public object Load(System.Type entityClass, object id) return Load(entityClass.FullName, id); } + /// public T Get(object id) { - using (BeginProcess()) - { - return (T)Get(typeof(T), id); - } + return (T) Get(typeof(T), id); } + /// public T Get(object id, LockMode lockMode) { - using (BeginProcess()) - { - return (T)Get(typeof(T), id, lockMode); - } + return (T) Get(typeof(T), id, lockMode); } + /// public object Get(System.Type entityClass, object id) { return Get(entityClass.FullName, id); } - /// - /// Load the data for the object with the specified id into a newly created object - /// using "for update", if supported. A new key will be assigned to the object. - /// This should return an existing proxy where appropriate. - /// - /// If the object does not exist in the database, null is returned. - /// - /// - /// - /// - /// + /// public object Get(System.Type clazz, object id, LockMode lockMode) + { + return Get(clazz.FullName, id, lockMode); + } + + /// + public object Get(string entityName, object id, LockMode lockMode) { using (BeginProcess()) { - LoadEvent loadEvent = new LoadEvent(id, clazz.FullName, lockMode, this); + LoadEvent loadEvent = new LoadEvent(id, entityName, lockMode, this); FireLoad(loadEvent, LoadEventListener.Get); + //Note: AfterOperation call is skipped to avoid releasing the lock when outside of a transaction. return loadEvent.Result; } } + /// + public object Get(string entityName, object id) + { + using (BeginProcess()) + { + LoadEvent loadEvent = new LoadEvent(id, entityName, null, this); + bool success = false; + try + { + FireLoad(loadEvent, LoadEventListener.Get); + success = true; + return loadEvent.Result; + } + finally + { + AfterOperation(success); + } + } + } + public string GetEntityName(object obj) { using (BeginProcess()) @@ -1226,25 +1240,6 @@ public string GetEntityName(object obj) } } - public object Get(string entityName, object id) - { - using (BeginProcess()) - { - LoadEvent loadEvent = new LoadEvent(id, entityName, false, this); - bool success = false; - try - { - FireLoad(loadEvent, LoadEventListener.Get); - success = true; - return loadEvent.Result; - } - finally - { - AfterOperation(success); - } - } - } - /// /// Load the data for the object with the specified id into a newly created object. /// This is only called when lazily initializing a proxy. diff --git a/src/NHibernate/Impl/StatelessSessionImpl.cs b/src/NHibernate/Impl/StatelessSessionImpl.cs index 12ff0fde552..b42b746b593 100644 --- a/src/NHibernate/Impl/StatelessSessionImpl.cs +++ b/src/NHibernate/Impl/StatelessSessionImpl.cs @@ -539,40 +539,32 @@ public void Delete(string entityName, object entity) } } - /// Retrieve a entity. + /// Retrieve an entity. /// a detached entity instance public object Get(string entityName, object id) { return Get(entityName, id, LockMode.None); } - /// Retrieve a entity. - /// + /// + /// Retrieve an entity. /// /// a detached entity instance /// public T Get(object id) { - using (BeginProcess()) - { - return (T)Get(typeof(T), id); - } - } - - private object Get(System.Type persistentClass, object id) - { - return Get(persistentClass.FullName, id); + return (T) Get(typeof(T).FullName, id); } /// - /// Retrieve a entity, obtaining the specified lock mode. + /// Retrieve an entity, obtaining the specified lock mode. /// /// a detached entity instance public object Get(string entityName, object id, LockMode lockMode) { using (BeginProcess()) { - object result = Factory.GetEntityPersister(entityName).Load(id, null, lockMode, this); + object result = Factory.GetEntityPersister(entityName).Load(id, null, lockMode ?? LockMode.None, this); if (temporaryPersistenceContext.IsLoadFinished) { temporaryPersistenceContext.Clear(); @@ -582,15 +574,12 @@ public object Get(string entityName, object id, LockMode lockMode) } /// - /// Retrieve a entity, obtaining the specified lock mode. + /// Retrieve an entity, obtaining the specified lock mode. /// /// a detached entity instance public T Get(object id, LockMode lockMode) { - using (BeginProcess()) - { - return (T)Get(typeof(T).FullName, id, lockMode); - } + return (T) Get(typeof(T).FullName, id, lockMode); } ///