From a9e7038e390dbf2d5e82f7924160a45ac7acb0de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericdelaporte@users.noreply.github.com> Date: Sun, 10 Apr 2022 17:16:39 +0200 Subject: [PATCH 1/5] Add test case for query on delayed id Test #3041 --- .../Identity/IdentityGeneratedKeysTest.cs | 55 ++++++++++-- .../Generatedkeys/Identity/MyEntity.hbm.xml | 86 +++++++++---------- 2 files changed, 93 insertions(+), 48 deletions(-) diff --git a/src/NHibernate.Test/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs b/src/NHibernate.Test/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs index 3eaf6de36ca..56f2a3a9272 100644 --- a/src/NHibernate.Test/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs +++ b/src/NHibernate.Test/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs @@ -1,4 +1,6 @@ +using System.Linq; using NHibernate.Cfg; +using NHibernate.Exceptions; using NUnit.Framework; namespace NHibernate.Test.Generatedkeys.Identity @@ -27,6 +29,19 @@ protected override void Configure(Configuration configuration) configuration.SetProperty(Environment.GenerateStatistics, "true"); } + protected override void OnTearDown() + { + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + s.CreateQuery("delete from MyChild").ExecuteUpdate(); + s.CreateQuery("delete from MySibling").ExecuteUpdate(); + s.CreateQuery("delete from System.Object").ExecuteUpdate(); + t.Commit(); + s.Close(); + } + } + [Test] public void IdentityColumnGeneratedIds() { @@ -43,7 +58,7 @@ public void IdentityColumnGeneratedIds() } } - [Test, Ignore("Not supported yet.")] + [Test] public void PersistOutsideTransaction() { var myEntity1 = new MyEntity("test-save"); @@ -83,7 +98,7 @@ public void PersistOutsideTransaction() } } - [Test, Ignore("Not supported yet.")] + [Test] public void PersistOutsideTransactionCascadedToNonInverseCollection() { long initialInsertCount = Sfi.Statistics.EntityInsertCount; @@ -115,7 +130,7 @@ public void PersistOutsideTransactionCascadedToNonInverseCollection() } } - [Test, Ignore("Not supported yet.")] + [Test] public void PersistOutsideTransactionCascadedToInverseCollection() { long initialInsertCount = Sfi.Statistics.EntityInsertCount; @@ -149,7 +164,7 @@ public void PersistOutsideTransactionCascadedToInverseCollection() } } - [Test, Ignore("Not supported yet.")] + [Test] public void PersistOutsideTransactionCascadedToManyToOne() { long initialInsertCount = Sfi.Statistics.EntityInsertCount; @@ -181,7 +196,7 @@ public void PersistOutsideTransactionCascadedToManyToOne() } } - [Test, Ignore("Not supported yet.")] + [Test] public void PersistOutsideTransactionCascadedFromManyToOne() { long initialInsertCount = Sfi.Statistics.EntityInsertCount; @@ -213,5 +228,35 @@ public void PersistOutsideTransactionCascadedFromManyToOne() s.Close(); } } + + [Test] + public void QueryOnPersistedEntity([Values(FlushMode.Auto, FlushMode.Commit)] FlushMode flushMode) + { + var myEntity = new MyEntity("test-persist"); + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + s.FlushMode = flushMode; + + var initialInsertCount = Sfi.Statistics.EntityInsertCount; + s.Persist(myEntity); + Assert.That(Sfi.Statistics.EntityInsertCount, Is.EqualTo(initialInsertCount), + "persist on identity column not delayed"); + Assert.That(myEntity.Id, Is.Zero); + + var query = s.Query().Where(c => c.InverseParent == myEntity); + switch (flushMode) + { + case FlushMode.Auto: + Assert.That(query.ToList, Throws.Nothing); + break; + case FlushMode.Commit: + Assert.That(query.ToList, Throws.Exception.TypeOf(typeof(HibernateException)).And.Not.TypeOf(typeof(GenericADOException))); + break; + } + t.Commit(); + s.Close(); + } + } } } diff --git a/src/NHibernate.Test/Generatedkeys/Identity/MyEntity.hbm.xml b/src/NHibernate.Test/Generatedkeys/Identity/MyEntity.hbm.xml index 0b1deccdfdb..00918675ee8 100644 --- a/src/NHibernate.Test/Generatedkeys/Identity/MyEntity.hbm.xml +++ b/src/NHibernate.Test/Generatedkeys/Identity/MyEntity.hbm.xml @@ -1,45 +1,45 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + assembly="NHibernate.Test" + namespace="NHibernate.Test.Generatedkeys.Identity"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From ae3abf38add4d1c97ef675333ab97ff44ebf076e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericdelaporte@users.noreply.github.com> Date: Sun, 10 Apr 2022 18:03:39 +0200 Subject: [PATCH 2/5] Regenerate async code --- .../Identity/IdentityGeneratedKeysTest.cs | 216 ++++++++++++++++++ 1 file changed, 216 insertions(+) diff --git a/src/NHibernate.Test/Async/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs b/src/NHibernate.Test/Async/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs index b927eeb17b9..cdb06fac28d 100644 --- a/src/NHibernate.Test/Async/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs +++ b/src/NHibernate.Test/Async/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs @@ -8,7 +8,9 @@ //------------------------------------------------------------------------------ +using System.Linq; using NHibernate.Cfg; +using NHibernate.Exceptions; using NUnit.Framework; namespace NHibernate.Test.Generatedkeys.Identity @@ -38,6 +40,19 @@ protected override void Configure(Configuration configuration) configuration.SetProperty(Environment.GenerateStatistics, "true"); } + protected override void OnTearDown() + { + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + s.CreateQuery("delete from MyChild").ExecuteUpdate(); + s.CreateQuery("delete from MySibling").ExecuteUpdate(); + s.CreateQuery("delete from System.Object").ExecuteUpdate(); + t.Commit(); + s.Close(); + } + } + [Test] public async Task IdentityColumnGeneratedIdsAsync() { @@ -53,5 +68,206 @@ public async Task IdentityColumnGeneratedIdsAsync() s.Close(); } } + + [Test] + public async Task PersistOutsideTransactionAsync() + { + var myEntity1 = new MyEntity("test-save"); + var myEntity2 = new MyEntity("test-persist"); + using (var s = OpenSession()) + { + // first test save() which should force an immediate insert... + long id = (long) await (s.SaveAsync(myEntity1)); + Assert.IsNotNull(id, "identity column did not force immediate insert"); + Assert.AreEqual(id, myEntity1.Id); + + // next test persist() which should cause a delayed insert... + long initialInsertCount = Sfi.Statistics.EntityInsertCount; + await (s.PersistAsync(myEntity2)); + Assert.AreEqual( + initialInsertCount, + Sfi.Statistics.EntityInsertCount, + "persist on identity column not delayed"); + Assert.AreEqual(0, myEntity2.Id); + + // an explicit flush should cause execution of the delayed insertion + await (s.FlushAsync()); + Assert.AreEqual( + initialInsertCount + 1, + Sfi.Statistics.EntityInsertCount, + "delayed persist insert not executed on flush"); + s.Close(); + } + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + await (s.DeleteAsync(myEntity1)); + await (s.DeleteAsync(myEntity2)); + await (t.CommitAsync()); + s.Close(); + } + } + + [Test] + public async Task PersistOutsideTransactionCascadedToNonInverseCollectionAsync() + { + long initialInsertCount = Sfi.Statistics.EntityInsertCount; + using (var s = OpenSession()) + { + MyEntity myEntity = new MyEntity("test-persist"); + myEntity.NonInverseChildren.Add(new MyChild("test-child-persist-non-inverse")); + await (s.PersistAsync(myEntity)); + Assert.AreEqual( + initialInsertCount, + Sfi.Statistics.EntityInsertCount, + "persist on identity column not delayed"); + Assert.AreEqual(0, myEntity.Id); + await (s.FlushAsync()); + Assert.AreEqual( + initialInsertCount + 2, + Sfi.Statistics.EntityInsertCount, + "delayed persist insert not executed on flush"); + s.Close(); + } + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + await (s.DeleteAsync("from MyChild")); + await (s.DeleteAsync("from MyEntity")); + await (t.CommitAsync()); + s.Close(); + } + } + + [Test] + public async Task PersistOutsideTransactionCascadedToInverseCollectionAsync() + { + long initialInsertCount = Sfi.Statistics.EntityInsertCount; + using (var s = OpenSession()) + { + MyEntity myEntity2 = new MyEntity("test-persist-2"); + MyChild child = new MyChild("test-child-persist-inverse"); + myEntity2.InverseChildren.Add(child); + child.InverseParent = myEntity2; + await (s.PersistAsync(myEntity2)); + Assert.AreEqual( + initialInsertCount, + Sfi.Statistics.EntityInsertCount, + "persist on identity column not delayed"); + Assert.AreEqual(0, myEntity2.Id); + await (s.FlushAsync()); + Assert.AreEqual( + initialInsertCount + 2, + Sfi.Statistics.EntityInsertCount, + "delayed persist insert not executed on flush"); + s.Close(); + } + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + await (s.DeleteAsync("from MyChild")); + await (s.DeleteAsync("from MyEntity")); + await (t.CommitAsync()); + s.Close(); + } + } + + [Test] + public async Task PersistOutsideTransactionCascadedToManyToOneAsync() + { + long initialInsertCount = Sfi.Statistics.EntityInsertCount; + using (var s = OpenSession()) + { + MyEntity myEntity = new MyEntity("test-persist"); + myEntity.Sibling = new MySibling("test-persist-sibling-out"); + await (s.PersistAsync(myEntity)); + Assert.AreEqual( + initialInsertCount, + Sfi.Statistics.EntityInsertCount, + "persist on identity column not delayed"); + Assert.AreEqual(0, myEntity.Id); + await (s.FlushAsync()); + Assert.AreEqual( + initialInsertCount + 2, + Sfi.Statistics.EntityInsertCount, + "delayed persist insert not executed on flush"); + s.Close(); + } + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + await (s.DeleteAsync("from MyEntity")); + await (s.DeleteAsync("from MySibling")); + await (t.CommitAsync()); + s.Close(); + } + } + + [Test] + public async Task PersistOutsideTransactionCascadedFromManyToOneAsync() + { + long initialInsertCount = Sfi.Statistics.EntityInsertCount; + using (var s = OpenSession()) + { + MyEntity myEntity2 = new MyEntity("test-persist-2"); + MySibling sibling = new MySibling("test-persist-sibling-in"); + sibling.Entity = myEntity2; + await (s.PersistAsync(sibling)); + Assert.AreEqual( + initialInsertCount, + Sfi.Statistics.EntityInsertCount, + "persist on identity column not delayed"); + Assert.AreEqual(0, myEntity2.Id); + await (s.FlushAsync()); + Assert.AreEqual( + initialInsertCount + 2, + Sfi.Statistics.EntityInsertCount, + "delayed persist insert not executed on flush"); + s.Close(); + } + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + await (s.DeleteAsync("from MySibling")); + await (s.DeleteAsync("from MyEntity")); + await (t.CommitAsync()); + s.Close(); + } + } + + [Test] + public async Task QueryOnPersistedEntityAsync([Values(FlushMode.Auto, FlushMode.Commit)] FlushMode flushMode) + { + var myEntity = new MyEntity("test-persist"); + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + s.FlushMode = flushMode; + + var initialInsertCount = Sfi.Statistics.EntityInsertCount; + await (s.PersistAsync(myEntity)); + Assert.That(Sfi.Statistics.EntityInsertCount, Is.EqualTo(initialInsertCount), + "persist on identity column not delayed"); + Assert.That(myEntity.Id, Is.Zero); + + var query = s.Query().Where(c => c.InverseParent == myEntity); + switch (flushMode) + { + case FlushMode.Auto: + Assert.That(query.ToList, Throws.Nothing); + break; + case FlushMode.Commit: + Assert.That(query.ToList, Throws.Exception.TypeOf(typeof(HibernateException)).And.Not.TypeOf(typeof(GenericADOException))); + break; + } + await (t.CommitAsync()); + s.Close(); + } + } } } From 1735f8e951917afdb405c4e6e518804120937e44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericdelaporte@users.noreply.github.com> Date: Sun, 17 Apr 2022 13:27:27 +0200 Subject: [PATCH 3/5] Raise a better exception for queries on delayed identifiers --- .../Identity/IdentityGeneratedKeysTest.cs | 2 +- .../Identity/IdentityGeneratedKeysTest.cs | 2 +- src/NHibernate/Async/Type/EntityType.cs | 13 +++++++++++++ src/NHibernate/Async/Type/ManyToOneType.cs | 4 ++-- src/NHibernate/Async/Type/OneToOneType.cs | 2 +- src/NHibernate/Type/EntityType.cs | 12 ++++++++++++ src/NHibernate/Type/ManyToOneType.cs | 4 ++-- src/NHibernate/Type/OneToOneType.cs | 2 +- 8 files changed, 33 insertions(+), 8 deletions(-) diff --git a/src/NHibernate.Test/Async/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs b/src/NHibernate.Test/Async/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs index cdb06fac28d..1c0bc4d54dd 100644 --- a/src/NHibernate.Test/Async/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs +++ b/src/NHibernate.Test/Async/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs @@ -262,7 +262,7 @@ public async Task QueryOnPersistedEntityAsync([Values(FlushMode.Auto, FlushMode. Assert.That(query.ToList, Throws.Nothing); break; case FlushMode.Commit: - Assert.That(query.ToList, Throws.Exception.TypeOf(typeof(HibernateException)).And.Not.TypeOf(typeof(GenericADOException))); + Assert.That(query.ToList, Throws.Exception.TypeOf(typeof(UnresolvableObjectException))); break; } await (t.CommitAsync()); diff --git a/src/NHibernate.Test/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs b/src/NHibernate.Test/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs index 56f2a3a9272..e566542d747 100644 --- a/src/NHibernate.Test/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs +++ b/src/NHibernate.Test/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs @@ -251,7 +251,7 @@ public void QueryOnPersistedEntity([Values(FlushMode.Auto, FlushMode.Commit)] Fl Assert.That(query.ToList, Throws.Nothing); break; case FlushMode.Commit: - Assert.That(query.ToList, Throws.Exception.TypeOf(typeof(HibernateException)).And.Not.TypeOf(typeof(GenericADOException))); + Assert.That(query.ToList, Throws.Exception.TypeOf(typeof(UnresolvableObjectException))); break; } t.Commit(); diff --git a/src/NHibernate/Async/Type/EntityType.cs b/src/NHibernate/Async/Type/EntityType.cs index 95fa8eaa2bb..b39c7659f49 100644 --- a/src/NHibernate/Async/Type/EntityType.cs +++ b/src/NHibernate/Async/Type/EntityType.cs @@ -18,6 +18,7 @@ using NHibernate.Proxy; using NHibernate.Util; using System.Collections.Generic; +using NHibernate.Action; namespace NHibernate.Type { @@ -80,6 +81,18 @@ protected internal async Task GetReferenceValueAsync(object value, ISess } } + protected internal async Task GetReferenceValueAsync(object value, ISessionImplementor session, bool forbidDelayed, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + var referenceValue = await (GetReferenceValueAsync(value, session, cancellationToken)).ConfigureAwait(false); + if (forbidDelayed && referenceValue is DelayedPostInsertIdentifier) + throw new UnresolvableObjectException( + $"Cannot resolve the identifier from a {nameof(DelayedPostInsertIdentifier)}. Consider flushing the session first.", + referenceValue, returnedClass); + + return referenceValue; + } + public override async Task ReplaceAsync(object original, object target, ISessionImplementor session, object owner, IDictionary copyCache, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); diff --git a/src/NHibernate/Async/Type/ManyToOneType.cs b/src/NHibernate/Async/Type/ManyToOneType.cs index d5615a85d7a..66c332ffe6c 100644 --- a/src/NHibernate/Async/Type/ManyToOneType.cs +++ b/src/NHibernate/Async/Type/ManyToOneType.cs @@ -26,14 +26,14 @@ public override async Task NullSafeSetAsync(DbCommand st, object value, int inde { cancellationToken.ThrowIfCancellationRequested(); await (GetIdentifierOrUniqueKeyType(session.Factory) - .NullSafeSetAsync(st, await (GetReferenceValueAsync(value, session, cancellationToken)).ConfigureAwait(false), index, settable, session, cancellationToken)).ConfigureAwait(false); + .NullSafeSetAsync(st, await (GetReferenceValueAsync(value, session, true, cancellationToken)).ConfigureAwait(false), index, settable, session, cancellationToken)).ConfigureAwait(false); } public override async Task NullSafeSetAsync(DbCommand cmd, object value, int index, ISessionImplementor session, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); await (GetIdentifierOrUniqueKeyType(session.Factory) - .NullSafeSetAsync(cmd, await (GetReferenceValueAsync(value, session, cancellationToken)).ConfigureAwait(false), index, session, cancellationToken)).ConfigureAwait(false); + .NullSafeSetAsync(cmd, await (GetReferenceValueAsync(value, session, true, cancellationToken)).ConfigureAwait(false), index, session, cancellationToken)).ConfigureAwait(false); } /// diff --git a/src/NHibernate/Async/Type/OneToOneType.cs b/src/NHibernate/Async/Type/OneToOneType.cs index d53f9c968d2..dc5edd36b36 100644 --- a/src/NHibernate/Async/Type/OneToOneType.cs +++ b/src/NHibernate/Async/Type/OneToOneType.cs @@ -43,7 +43,7 @@ public override async Task NullSafeSetAsync(DbCommand cmd, object value, int ind { cancellationToken.ThrowIfCancellationRequested(); await (GetIdentifierOrUniqueKeyType(session.Factory) - .NullSafeSetAsync(cmd, await (GetReferenceValueAsync(value, session, cancellationToken)).ConfigureAwait(false), index, session, cancellationToken)).ConfigureAwait(false); + .NullSafeSetAsync(cmd, await (GetReferenceValueAsync(value, session, true, cancellationToken)).ConfigureAwait(false), index, session, cancellationToken)).ConfigureAwait(false); } public override Task IsDirtyAsync(object old, object current, ISessionImplementor session, CancellationToken cancellationToken) diff --git a/src/NHibernate/Type/EntityType.cs b/src/NHibernate/Type/EntityType.cs index b45502fc914..45aaab29195 100644 --- a/src/NHibernate/Type/EntityType.cs +++ b/src/NHibernate/Type/EntityType.cs @@ -8,6 +8,7 @@ using NHibernate.Proxy; using NHibernate.Util; using System.Collections.Generic; +using NHibernate.Action; namespace NHibernate.Type { @@ -185,6 +186,17 @@ protected internal object GetReferenceValue(object value, ISessionImplementor se } } + protected internal object GetReferenceValue(object value, ISessionImplementor session, bool forbidDelayed) + { + var referenceValue = GetReferenceValue(value, session); + if (forbidDelayed && referenceValue is DelayedPostInsertIdentifier) + throw new UnresolvableObjectException( + $"Cannot resolve the identifier from a {nameof(DelayedPostInsertIdentifier)}. Consider flushing the session first.", + referenceValue, returnedClass); + + return referenceValue; + } + public override string ToLoggableString(object value, ISessionFactoryImplementor factory) { if (value == null) diff --git a/src/NHibernate/Type/ManyToOneType.cs b/src/NHibernate/Type/ManyToOneType.cs index 172bc8f1b99..47e01b10269 100644 --- a/src/NHibernate/Type/ManyToOneType.cs +++ b/src/NHibernate/Type/ManyToOneType.cs @@ -58,13 +58,13 @@ public override SqlType[] SqlTypes(IMapping mapping) public override void NullSafeSet(DbCommand st, object value, int index, bool[] settable, ISessionImplementor session) { GetIdentifierOrUniqueKeyType(session.Factory) - .NullSafeSet(st, GetReferenceValue(value, session), index, settable, session); + .NullSafeSet(st, GetReferenceValue(value, session, true), index, settable, session); } public override void NullSafeSet(DbCommand cmd, object value, int index, ISessionImplementor session) { GetIdentifierOrUniqueKeyType(session.Factory) - .NullSafeSet(cmd, GetReferenceValue(value, session), index, session); + .NullSafeSet(cmd, GetReferenceValue(value, session, true), index, session); } public override bool IsOneToOne diff --git a/src/NHibernate/Type/OneToOneType.cs b/src/NHibernate/Type/OneToOneType.cs index 0837ea3b98a..7117b8bc329 100644 --- a/src/NHibernate/Type/OneToOneType.cs +++ b/src/NHibernate/Type/OneToOneType.cs @@ -49,7 +49,7 @@ public override void NullSafeSet(DbCommand st, object value, int index, bool[] s public override void NullSafeSet(DbCommand cmd, object value, int index, ISessionImplementor session) { GetIdentifierOrUniqueKeyType(session.Factory) - .NullSafeSet(cmd, GetReferenceValue(value, session), index, session); + .NullSafeSet(cmd, GetReferenceValue(value, session, true), index, session); } public override bool IsOneToOne From 7fa2343799b26c1d19c65743552d64648c475b8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericdelaporte@users.noreply.github.com> Date: Mon, 18 Apr 2022 14:27:39 +0200 Subject: [PATCH 4/5] Add missing braces --- src/NHibernate/Async/Type/EntityType.cs | 2 ++ src/NHibernate/Type/EntityType.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/NHibernate/Async/Type/EntityType.cs b/src/NHibernate/Async/Type/EntityType.cs index b39c7659f49..dffe868962e 100644 --- a/src/NHibernate/Async/Type/EntityType.cs +++ b/src/NHibernate/Async/Type/EntityType.cs @@ -86,9 +86,11 @@ protected internal async Task GetReferenceValueAsync(object value, ISess cancellationToken.ThrowIfCancellationRequested(); var referenceValue = await (GetReferenceValueAsync(value, session, cancellationToken)).ConfigureAwait(false); if (forbidDelayed && referenceValue is DelayedPostInsertIdentifier) + { throw new UnresolvableObjectException( $"Cannot resolve the identifier from a {nameof(DelayedPostInsertIdentifier)}. Consider flushing the session first.", referenceValue, returnedClass); + } return referenceValue; } diff --git a/src/NHibernate/Type/EntityType.cs b/src/NHibernate/Type/EntityType.cs index 45aaab29195..5d5b3e29e90 100644 --- a/src/NHibernate/Type/EntityType.cs +++ b/src/NHibernate/Type/EntityType.cs @@ -190,9 +190,11 @@ protected internal object GetReferenceValue(object value, ISessionImplementor se { var referenceValue = GetReferenceValue(value, session); if (forbidDelayed && referenceValue is DelayedPostInsertIdentifier) + { throw new UnresolvableObjectException( $"Cannot resolve the identifier from a {nameof(DelayedPostInsertIdentifier)}. Consider flushing the session first.", referenceValue, returnedClass); + } return referenceValue; } From 44a157565fd2ee2876838e39850ce3ef072db0a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericdelaporte@users.noreply.github.com> Date: Mon, 18 Apr 2022 18:17:35 +0200 Subject: [PATCH 5/5] Fix an invalid test --- .../Identity/IdentityGeneratedKeysTest.cs | 25 ++++++++++++------- .../Identity/IdentityGeneratedKeysTest.cs | 25 ++++++++++++------- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/NHibernate.Test/Async/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs b/src/NHibernate.Test/Async/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs index 1c0bc4d54dd..9756052f341 100644 --- a/src/NHibernate.Test/Async/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs +++ b/src/NHibernate.Test/Async/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs @@ -59,11 +59,14 @@ public async Task IdentityColumnGeneratedIdsAsync() using (var s = OpenSession()) using (var t = s.BeginTransaction()) { - MyEntity myEntity = new MyEntity("test"); - long id = (long) await (s.SaveAsync(myEntity)); - Assert.IsNotNull(id, "identity column did not force immediate insert"); - Assert.AreEqual(id, myEntity.Id); - await (s.DeleteAsync(myEntity)); + var entity1 = new MyEntity("test"); + var id1 = (long) await (s.SaveAsync(entity1)); + var entity2 = new MyEntity("test2"); + var id2 = (long) await (s.SaveAsync(entity2)); + // As 0 may be a valid identity value, we check for returned ids being not the same when saving two entities. + Assert.That(id1, Is.Not.EqualTo(id2), "identity column did not force immediate insert"); + Assert.That(id1, Is.EqualTo(entity1.Id)); + Assert.That(id2, Is.EqualTo(entity2.Id)); await (t.CommitAsync()); s.Close(); } @@ -77,12 +80,16 @@ public async Task PersistOutsideTransactionAsync() using (var s = OpenSession()) { // first test save() which should force an immediate insert... - long id = (long) await (s.SaveAsync(myEntity1)); - Assert.IsNotNull(id, "identity column did not force immediate insert"); - Assert.AreEqual(id, myEntity1.Id); + var initialInsertCount = Sfi.Statistics.EntityInsertCount; + var id = (long) await (s.SaveAsync(myEntity1)); + Assert.That( + Sfi.Statistics.EntityInsertCount, + Is.GreaterThan(initialInsertCount), + "identity column did not force immediate insert"); + Assert.That(id, Is.EqualTo(myEntity1.Id)); // next test persist() which should cause a delayed insert... - long initialInsertCount = Sfi.Statistics.EntityInsertCount; + initialInsertCount = Sfi.Statistics.EntityInsertCount; await (s.PersistAsync(myEntity2)); Assert.AreEqual( initialInsertCount, diff --git a/src/NHibernate.Test/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs b/src/NHibernate.Test/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs index e566542d747..7eb3f8eb7d6 100644 --- a/src/NHibernate.Test/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs +++ b/src/NHibernate.Test/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs @@ -48,11 +48,14 @@ public void IdentityColumnGeneratedIds() using (var s = OpenSession()) using (var t = s.BeginTransaction()) { - MyEntity myEntity = new MyEntity("test"); - long id = (long) s.Save(myEntity); - Assert.IsNotNull(id, "identity column did not force immediate insert"); - Assert.AreEqual(id, myEntity.Id); - s.Delete(myEntity); + var entity1 = new MyEntity("test"); + var id1 = (long) s.Save(entity1); + var entity2 = new MyEntity("test2"); + var id2 = (long) s.Save(entity2); + // As 0 may be a valid identity value, we check for returned ids being not the same when saving two entities. + Assert.That(id1, Is.Not.EqualTo(id2), "identity column did not force immediate insert"); + Assert.That(id1, Is.EqualTo(entity1.Id)); + Assert.That(id2, Is.EqualTo(entity2.Id)); t.Commit(); s.Close(); } @@ -66,12 +69,16 @@ public void PersistOutsideTransaction() using (var s = OpenSession()) { // first test save() which should force an immediate insert... - long id = (long) s.Save(myEntity1); - Assert.IsNotNull(id, "identity column did not force immediate insert"); - Assert.AreEqual(id, myEntity1.Id); + var initialInsertCount = Sfi.Statistics.EntityInsertCount; + var id = (long) s.Save(myEntity1); + Assert.That( + Sfi.Statistics.EntityInsertCount, + Is.GreaterThan(initialInsertCount), + "identity column did not force immediate insert"); + Assert.That(id, Is.EqualTo(myEntity1.Id)); // next test persist() which should cause a delayed insert... - long initialInsertCount = Sfi.Statistics.EntityInsertCount; + initialInsertCount = Sfi.Statistics.EntityInsertCount; s.Persist(myEntity2); Assert.AreEqual( initialInsertCount,