From 2164f29541cb71a646eeb311ec53fe4c89991117 Mon Sep 17 00:00:00 2001 From: CSharper2010 Date: Mon, 19 Jun 2023 12:03:46 +0200 Subject: [PATCH 01/14] Fixes #3325 VisitCollectionsBeforeSave must be called no matter if substitute is already true. On versioned entities this is always the case. --- .../NHSpecificTest/GHXYZ/Entity.cs | 26 +++++++ .../NHSpecificTest/GHXYZ/Fixture.cs | 57 +++++++++++++++ .../NHSpecificTest/GHXYZ/Mappings.hbm.xml | 31 ++++++++ .../NHSpecificTest/GHXYZ/PersistentSetType.cs | 71 +++++++++++++++++++ .../Default/AbstractSaveEventListener.cs | 2 +- 5 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 src/NHibernate.Test/NHSpecificTest/GHXYZ/Entity.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GHXYZ/Fixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GHXYZ/Mappings.hbm.xml create mode 100644 src/NHibernate.Test/NHSpecificTest/GHXYZ/PersistentSetType.cs diff --git a/src/NHibernate.Test/NHSpecificTest/GHXYZ/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GHXYZ/Entity.cs new file mode 100644 index 00000000000..e30fdec19d4 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GHXYZ/Entity.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; + +namespace NHibernate.Test.NHSpecificTest.GHXYZ +{ + public class Entity + { + public virtual Guid Id { get; set; } + public virtual int Version { get; set; } = -1; + public virtual string Name { get; set; } + public virtual ISet Children { get; set; } = new HashSet(); + } + + public class EntityWithoutDeleteOrphan + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + public virtual ISet Children { get; set; } = new HashSet(); + } + + public class ChildEntity + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GHXYZ/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GHXYZ/Fixture.cs new file mode 100644 index 00000000000..ce0634c607f --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GHXYZ/Fixture.cs @@ -0,0 +1,57 @@ +using System; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GHXYZ +{ + [TestFixture] + public class Fixture : BugTestCase + { + protected override void OnSetUp() + { + Sfi.Statistics.IsStatisticsEnabled = true; + } + + protected override void OnTearDown() + { + Sfi.Statistics.IsStatisticsEnabled = false; + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + session.CreateQuery("delete from ChildEntity").ExecuteUpdate(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + } + + [Test] + public void CanAddChildAfterFlush() + { + Guid parentId; + Guid childId; + using (var session = OpenSession()) + using (var t = session.BeginTransaction()) + { + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + parent.Children.Add(child); + session.Save(parent); + parent.Children.Remove(child); + parentId = parent.Id; + childId = child.Id; + t.Commit(); + } + + using (var session = OpenSession()) + using (var _ = session.BeginTransaction()) + { + var parent = session.Get(parentId); + Assert.That(parent, Is.Not.Null); + Assert.That(parent.Children, Has.Count.EqualTo(0)); + + var child = session.Get(childId); + Assert.That(child, Is.Null); + } + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GHXYZ/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GHXYZ/Mappings.hbm.xml new file mode 100644 index 00000000000..a0fdd81a534 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GHXYZ/Mappings.hbm.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/NHibernate.Test/NHSpecificTest/GHXYZ/PersistentSetType.cs b/src/NHibernate.Test/NHSpecificTest/GHXYZ/PersistentSetType.cs new file mode 100644 index 00000000000..13a064c1f17 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GHXYZ/PersistentSetType.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using NHibernate.Collection; +using NHibernate.Collection.Generic; +using NHibernate.Engine; +using NHibernate.Persister.Collection; +using NHibernate.UserTypes; + +namespace NHibernate.Test.NHSpecificTest.GHXYZ +{ + public class PersistentSetType : IUserCollectionType { + IPersistentCollection IUserCollectionType.Instantiate(ISessionImplementor session, ICollectionPersister persister) { + return new PersistentGenericSet(session); + } + + IPersistentCollection IUserCollectionType.Wrap(ISessionImplementor session, object collection) { + return new PersistentGenericSet(session, (ISet) collection); + } + + object IUserCollectionType.ReplaceElements(object original, object target, ICollectionPersister persister, object owner, IDictionary copyCache, ISessionImplementor session) { + object result = target; + Clear(result); + + foreach (object obj in (IEnumerable) original) { + Add(result, CopyElement(persister, obj, session, owner, copyCache)); + } + + return result; + } + + protected virtual object CopyElement(ICollectionPersister persister, object element, ISessionImplementor session, + object owner, IDictionary copiedAlready) { + return persister.ElementType.Replace(element, null, session, owner, copiedAlready); + } + + object IUserCollectionType.Instantiate(int anticipatedSize) { + return new HashSetWithICollection(); + } + + public IEnumerable GetElements(object collection) { + return (ISet) collection; + } + + public bool Contains(object collection, object entity) { + return ((ISet) collection).Contains((T) entity); + } + + public object IndexOf(object collection, object entity) { + throw new NotSupportedException(); + } + + protected virtual void Add(object collection, object element) { + ((ISet) collection).Add((T) element); + } + + protected virtual void Clear(object collection) { + ((ISet) collection).Clear(); + } + } + + public class HashSetWithICollection : HashSet, ICollection { + public void CopyTo(Array array, int index) { + this.Cast().ToArray().CopyTo(array, index); + } + + public object SyncRoot => this; + public bool IsSynchronized => false; + } +} diff --git a/src/NHibernate/Event/Default/AbstractSaveEventListener.cs b/src/NHibernate/Event/Default/AbstractSaveEventListener.cs index 8c9f356304f..b5e9c94b5bb 100644 --- a/src/NHibernate/Event/Default/AbstractSaveEventListener.cs +++ b/src/NHibernate/Event/Default/AbstractSaveEventListener.cs @@ -235,7 +235,7 @@ protected virtual object PerformSaveOrReplicate(object entity, EntityKey key, IE if (persister.HasCollections) { - substitute = substitute || VisitCollectionsBeforeSave(entity, id, values, types, source); + substitute = substitute | VisitCollectionsBeforeSave(entity, id, values, types, source); } if (substitute) From 70f7b9fbb67a64968455ca020eef4a5ed3f5da20 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 19 Jun 2023 10:08:03 +0000 Subject: [PATCH 02/14] Generate async files --- .../Async/NHSpecificTest/GHXYZ/Fixture.cs | 68 +++++++++++++++++++ .../Default/AbstractSaveEventListener.cs | 2 +- 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/GHXYZ/Fixture.cs diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GHXYZ/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GHXYZ/Fixture.cs new file mode 100644 index 00000000000..cd4b991f3ae --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GHXYZ/Fixture.cs @@ -0,0 +1,68 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GHXYZ +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + protected override void OnSetUp() + { + Sfi.Statistics.IsStatisticsEnabled = true; + } + + protected override void OnTearDown() + { + Sfi.Statistics.IsStatisticsEnabled = false; + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + session.CreateQuery("delete from ChildEntity").ExecuteUpdate(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + } + + [Test] + public async Task CanAddChildAfterFlushAsync() + { + Guid parentId; + Guid childId; + using (var session = OpenSession()) + using (var t = session.BeginTransaction()) + { + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + parent.Children.Add(child); + await (session.SaveAsync(parent)); + parent.Children.Remove(child); + parentId = parent.Id; + childId = child.Id; + await (t.CommitAsync()); + } + + using (var session = OpenSession()) + using (var _ = session.BeginTransaction()) + { + var parent = await (session.GetAsync(parentId)); + Assert.That(parent, Is.Not.Null); + Assert.That(parent.Children, Has.Count.EqualTo(0)); + + var child = await (session.GetAsync(childId)); + Assert.That(child, Is.Null); + } + } + } +} diff --git a/src/NHibernate/Async/Event/Default/AbstractSaveEventListener.cs b/src/NHibernate/Async/Event/Default/AbstractSaveEventListener.cs index f86e9a6c158..4b6553441c6 100644 --- a/src/NHibernate/Async/Event/Default/AbstractSaveEventListener.cs +++ b/src/NHibernate/Async/Event/Default/AbstractSaveEventListener.cs @@ -210,7 +210,7 @@ protected virtual async Task PerformSaveOrReplicateAsync(object entity, if (persister.HasCollections) { - substitute = substitute || await (VisitCollectionsBeforeSaveAsync(entity, id, values, types, source, cancellationToken)).ConfigureAwait(false); + substitute = substitute | await (VisitCollectionsBeforeSaveAsync(entity, id, values, types, source, cancellationToken)).ConfigureAwait(false); } if (substitute) From ec399615d51ea308a72ef80f6e7f3b73d7c4663d Mon Sep 17 00:00:00 2001 From: CSharper2010 Date: Tue, 20 Jun 2023 07:18:37 +0200 Subject: [PATCH 03/14] Fix Namespace --- src/NHibernate.Test/NHSpecificTest/{GHXYZ => GH3325}/Entity.cs | 2 +- src/NHibernate.Test/NHSpecificTest/{GHXYZ => GH3325}/Fixture.cs | 2 +- .../NHSpecificTest/{GHXYZ => GH3325}/Mappings.hbm.xml | 2 +- .../NHSpecificTest/{GHXYZ => GH3325}/PersistentSetType.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename src/NHibernate.Test/NHSpecificTest/{GHXYZ => GH3325}/Entity.cs (92%) rename src/NHibernate.Test/NHSpecificTest/{GHXYZ => GH3325}/Fixture.cs (96%) rename src/NHibernate.Test/NHSpecificTest/{GHXYZ => GH3325}/Mappings.hbm.xml (94%) rename src/NHibernate.Test/NHSpecificTest/{GHXYZ => GH3325}/PersistentSetType.cs (97%) diff --git a/src/NHibernate.Test/NHSpecificTest/GHXYZ/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3325/Entity.cs similarity index 92% rename from src/NHibernate.Test/NHSpecificTest/GHXYZ/Entity.cs rename to src/NHibernate.Test/NHSpecificTest/GH3325/Entity.cs index e30fdec19d4..e63e6c3819b 100644 --- a/src/NHibernate.Test/NHSpecificTest/GHXYZ/Entity.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3325/Entity.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace NHibernate.Test.NHSpecificTest.GHXYZ +namespace NHibernate.Test.NHSpecificTest.GH3325 { public class Entity { diff --git a/src/NHibernate.Test/NHSpecificTest/GHXYZ/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3325/Fixture.cs similarity index 96% rename from src/NHibernate.Test/NHSpecificTest/GHXYZ/Fixture.cs rename to src/NHibernate.Test/NHSpecificTest/GH3325/Fixture.cs index ce0634c607f..a0b6b1e5030 100644 --- a/src/NHibernate.Test/NHSpecificTest/GHXYZ/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3325/Fixture.cs @@ -1,7 +1,7 @@ using System; using NUnit.Framework; -namespace NHibernate.Test.NHSpecificTest.GHXYZ +namespace NHibernate.Test.NHSpecificTest.GH3325 { [TestFixture] public class Fixture : BugTestCase diff --git a/src/NHibernate.Test/NHSpecificTest/GHXYZ/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3325/Mappings.hbm.xml similarity index 94% rename from src/NHibernate.Test/NHSpecificTest/GHXYZ/Mappings.hbm.xml rename to src/NHibernate.Test/NHSpecificTest/GH3325/Mappings.hbm.xml index a0fdd81a534..0e94971f58b 100644 --- a/src/NHibernate.Test/NHSpecificTest/GHXYZ/Mappings.hbm.xml +++ b/src/NHibernate.Test/NHSpecificTest/GH3325/Mappings.hbm.xml @@ -1,6 +1,6 @@ + namespace="NHibernate.Test.NHSpecificTest.GH3325"> diff --git a/src/NHibernate.Test/NHSpecificTest/GHXYZ/PersistentSetType.cs b/src/NHibernate.Test/NHSpecificTest/GH3325/PersistentSetType.cs similarity index 97% rename from src/NHibernate.Test/NHSpecificTest/GHXYZ/PersistentSetType.cs rename to src/NHibernate.Test/NHSpecificTest/GH3325/PersistentSetType.cs index 13a064c1f17..d63f135f17c 100644 --- a/src/NHibernate.Test/NHSpecificTest/GHXYZ/PersistentSetType.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3325/PersistentSetType.cs @@ -8,7 +8,7 @@ using NHibernate.Persister.Collection; using NHibernate.UserTypes; -namespace NHibernate.Test.NHSpecificTest.GHXYZ +namespace NHibernate.Test.NHSpecificTest.GH3325 { public class PersistentSetType : IUserCollectionType { IPersistentCollection IUserCollectionType.Instantiate(ISessionImplementor session, ICollectionPersister persister) { From 36d4d440658f3603c7bf0d640115a7224c5b805d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 20 Jun 2023 05:22:16 +0000 Subject: [PATCH 04/14] Generate async files --- .../Async/NHSpecificTest/{GHXYZ => GH3325}/Fixture.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/NHibernate.Test/Async/NHSpecificTest/{GHXYZ => GH3325}/Fixture.cs (97%) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GHXYZ/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3325/Fixture.cs similarity index 97% rename from src/NHibernate.Test/Async/NHSpecificTest/GHXYZ/Fixture.cs rename to src/NHibernate.Test/Async/NHSpecificTest/GH3325/Fixture.cs index cd4b991f3ae..51c1a980fa4 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GHXYZ/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3325/Fixture.cs @@ -11,7 +11,7 @@ using System; using NUnit.Framework; -namespace NHibernate.Test.NHSpecificTest.GHXYZ +namespace NHibernate.Test.NHSpecificTest.GH3325 { using System.Threading.Tasks; [TestFixture] From 00d1bf2bda92f97f69f14124a5b848e512484660 Mon Sep 17 00:00:00 2001 From: CSharper2010 Date: Wed, 21 Jun 2023 10:15:20 +0200 Subject: [PATCH 05/14] Clean out custom collection because irrelevant for the problem --- .../NHSpecificTest/GH3325/Mappings.hbm.xml | 2 +- .../GH3325/PersistentSetType.cs | 71 ------------------- 2 files changed, 1 insertion(+), 72 deletions(-) delete mode 100644 src/NHibernate.Test/NHSpecificTest/GH3325/PersistentSetType.cs diff --git a/src/NHibernate.Test/NHSpecificTest/GH3325/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3325/Mappings.hbm.xml index 0e94971f58b..712bf46fb1f 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3325/Mappings.hbm.xml +++ b/src/NHibernate.Test/NHSpecificTest/GH3325/Mappings.hbm.xml @@ -6,7 +6,7 @@ - + diff --git a/src/NHibernate.Test/NHSpecificTest/GH3325/PersistentSetType.cs b/src/NHibernate.Test/NHSpecificTest/GH3325/PersistentSetType.cs deleted file mode 100644 index d63f135f17c..00000000000 --- a/src/NHibernate.Test/NHSpecificTest/GH3325/PersistentSetType.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using NHibernate.Collection; -using NHibernate.Collection.Generic; -using NHibernate.Engine; -using NHibernate.Persister.Collection; -using NHibernate.UserTypes; - -namespace NHibernate.Test.NHSpecificTest.GH3325 -{ - public class PersistentSetType : IUserCollectionType { - IPersistentCollection IUserCollectionType.Instantiate(ISessionImplementor session, ICollectionPersister persister) { - return new PersistentGenericSet(session); - } - - IPersistentCollection IUserCollectionType.Wrap(ISessionImplementor session, object collection) { - return new PersistentGenericSet(session, (ISet) collection); - } - - object IUserCollectionType.ReplaceElements(object original, object target, ICollectionPersister persister, object owner, IDictionary copyCache, ISessionImplementor session) { - object result = target; - Clear(result); - - foreach (object obj in (IEnumerable) original) { - Add(result, CopyElement(persister, obj, session, owner, copyCache)); - } - - return result; - } - - protected virtual object CopyElement(ICollectionPersister persister, object element, ISessionImplementor session, - object owner, IDictionary copiedAlready) { - return persister.ElementType.Replace(element, null, session, owner, copiedAlready); - } - - object IUserCollectionType.Instantiate(int anticipatedSize) { - return new HashSetWithICollection(); - } - - public IEnumerable GetElements(object collection) { - return (ISet) collection; - } - - public bool Contains(object collection, object entity) { - return ((ISet) collection).Contains((T) entity); - } - - public object IndexOf(object collection, object entity) { - throw new NotSupportedException(); - } - - protected virtual void Add(object collection, object element) { - ((ISet) collection).Add((T) element); - } - - protected virtual void Clear(object collection) { - ((ISet) collection).Clear(); - } - } - - public class HashSetWithICollection : HashSet, ICollection { - public void CopyTo(Array array, int index) { - this.Cast().ToArray().CopyTo(array, index); - } - - public object SyncRoot => this; - public bool IsSynchronized => false; - } -} From eaf89acccf448f00a56b74a6253d59daf260dde3 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Wed, 12 Jul 2023 13:54:58 +1000 Subject: [PATCH 06/14] Align fix with Hibernate and suggestions --- src/NHibernate/Event/Default/AbstractSaveEventListener.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NHibernate/Event/Default/AbstractSaveEventListener.cs b/src/NHibernate/Event/Default/AbstractSaveEventListener.cs index b5e9c94b5bb..cbec2218a22 100644 --- a/src/NHibernate/Event/Default/AbstractSaveEventListener.cs +++ b/src/NHibernate/Event/Default/AbstractSaveEventListener.cs @@ -235,7 +235,7 @@ protected virtual object PerformSaveOrReplicate(object entity, EntityKey key, IE if (persister.HasCollections) { - substitute = substitute | VisitCollectionsBeforeSave(entity, id, values, types, source); + substitute = VisitCollectionsBeforeSave(entity, id, values, types, source) || substitute; } if (substitute) From cf4e9a37ac5ea70e68cd25b297388068ed1a81a9 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Wed, 12 Jul 2023 15:05:26 +1000 Subject: [PATCH 07/14] Align tests with Hibernate --- .../AbstractEntityWithManyToManyTest.cs | 2 +- src/NHibernate.Test/ReadOnly/ReadOnlyVersionedNodes.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NHibernate.Test/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs b/src/NHibernate.Test/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs index 1e77060ab44..be22e24c08a 100644 --- a/src/NHibernate.Test/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs +++ b/src/NHibernate.Test/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs @@ -485,7 +485,7 @@ public void CreateWithNonEmptyManyToManyCollectionMergeWithNewElement() s.Close(); AssertInsertCount(1); - AssertUpdateCount(isContractVersioned && isPlanVersioned ? 1 : 0); // NH-specific: Hibernate issues a separate UPDATE for the version number + AssertUpdateCount(isContractVersioned && isPlanVersioned ? 2 : 0); ClearCounts(); s = OpenSession(); diff --git a/src/NHibernate.Test/ReadOnly/ReadOnlyVersionedNodes.cs b/src/NHibernate.Test/ReadOnly/ReadOnlyVersionedNodes.cs index 6ef31d2ae23..e038a2c5600 100644 --- a/src/NHibernate.Test/ReadOnly/ReadOnlyVersionedNodes.cs +++ b/src/NHibernate.Test/ReadOnly/ReadOnlyVersionedNodes.cs @@ -624,7 +624,7 @@ public void MergeDetachedChildWithNewParentCommitWithReadOnlyChild() t.Commit(); } - AssertUpdateCount(0); // NH-specific: Hibernate issues a separate UPDATE for the version number + AssertUpdateCount(1); AssertInsertCount(1); ClearCounts(); using (var s = OpenSession()) @@ -675,7 +675,7 @@ public void GetChildMakeReadOnlyThenMergeDetachedChildWithNewParent() t.Commit(); } - AssertUpdateCount(0); // NH-specific: Hibernate issues a separate UPDATE for the version number + AssertUpdateCount(1); AssertInsertCount(1); ClearCounts(); using (var s = OpenSession()) From 5cb796f593a36e5b4c5d0fa704ca5012b5eb14b7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 12 Jul 2023 05:10:48 +0000 Subject: [PATCH 08/14] Generate async files --- .../AbstractEntityWithManyToManyTest.cs | 2 +- src/NHibernate.Test/Async/ReadOnly/ReadOnlyVersionedNodes.cs | 4 ++-- .../Async/Event/Default/AbstractSaveEventListener.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/NHibernate.Test/Async/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs b/src/NHibernate.Test/Async/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs index a5e9222fd42..2432a8705c1 100644 --- a/src/NHibernate.Test/Async/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs +++ b/src/NHibernate.Test/Async/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs @@ -496,7 +496,7 @@ public async Task CreateWithNonEmptyManyToManyCollectionMergeWithNewElementAsync s.Close(); AssertInsertCount(1); - AssertUpdateCount(isContractVersioned && isPlanVersioned ? 1 : 0); // NH-specific: Hibernate issues a separate UPDATE for the version number + AssertUpdateCount(isContractVersioned && isPlanVersioned ? 2 : 0); ClearCounts(); s = OpenSession(); diff --git a/src/NHibernate.Test/Async/ReadOnly/ReadOnlyVersionedNodes.cs b/src/NHibernate.Test/Async/ReadOnly/ReadOnlyVersionedNodes.cs index def3e860c51..34732b41d40 100644 --- a/src/NHibernate.Test/Async/ReadOnly/ReadOnlyVersionedNodes.cs +++ b/src/NHibernate.Test/Async/ReadOnly/ReadOnlyVersionedNodes.cs @@ -558,7 +558,7 @@ public async Task MergeDetachedChildWithNewParentCommitWithReadOnlyChildAsync() await (t.CommitAsync()); } - AssertUpdateCount(0); // NH-specific: Hibernate issues a separate UPDATE for the version number + AssertUpdateCount(1); AssertInsertCount(1); ClearCounts(); using (var s = OpenSession()) @@ -609,7 +609,7 @@ public async Task GetChildMakeReadOnlyThenMergeDetachedChildWithNewParentAsync() await (t.CommitAsync()); } - AssertUpdateCount(0); // NH-specific: Hibernate issues a separate UPDATE for the version number + AssertUpdateCount(1); AssertInsertCount(1); ClearCounts(); using (var s = OpenSession()) diff --git a/src/NHibernate/Async/Event/Default/AbstractSaveEventListener.cs b/src/NHibernate/Async/Event/Default/AbstractSaveEventListener.cs index 4b6553441c6..0d7213cc0ad 100644 --- a/src/NHibernate/Async/Event/Default/AbstractSaveEventListener.cs +++ b/src/NHibernate/Async/Event/Default/AbstractSaveEventListener.cs @@ -210,7 +210,7 @@ protected virtual async Task PerformSaveOrReplicateAsync(object entity, if (persister.HasCollections) { - substitute = substitute | await (VisitCollectionsBeforeSaveAsync(entity, id, values, types, source, cancellationToken)).ConfigureAwait(false); + substitute = await (VisitCollectionsBeforeSaveAsync(entity, id, values, types, source, cancellationToken)).ConfigureAwait(false) || substitute; } if (substitute) From 8d85192de1d044779ff923fb10ed3fc7efcc99be Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Wed, 12 Jul 2023 16:27:16 +1000 Subject: [PATCH 09/14] Adjust test to Hibernate --- src/NHibernate.Test/ReadOnly/ReadOnlyVersionedNodes.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/NHibernate.Test/ReadOnly/ReadOnlyVersionedNodes.cs b/src/NHibernate.Test/ReadOnly/ReadOnlyVersionedNodes.cs index e038a2c5600..0773dd3e83e 100644 --- a/src/NHibernate.Test/ReadOnly/ReadOnlyVersionedNodes.cs +++ b/src/NHibernate.Test/ReadOnly/ReadOnlyVersionedNodes.cs @@ -637,7 +637,7 @@ public void MergeDetachedChildWithNewParentCommitWithReadOnlyChild() Assert.That(child.Version, Is.EqualTo(1)); Assert.That(parent, Is.Not.Null); Assert.That(parent.Children.Count, Is.EqualTo(0)); - Assert.That(parent.Version, Is.EqualTo(1)); + Assert.That(parent.Version, Is.EqualTo(2)); s.SetReadOnly(parent, true); s.SetReadOnly(child, true); s.Delete(parent); @@ -688,8 +688,7 @@ public void GetChildMakeReadOnlyThenMergeDetachedChildWithNewParent() Assert.That(child.Version, Is.EqualTo(1)); Assert.That(parent, Is.Not.Null); Assert.That(parent.Children.Count, Is.EqualTo(0)); - Assert.That(parent.Version, Is.EqualTo(1)); - // NH-specific: Hibernate incorrectly increments version number, NH does not + Assert.That(parent.Version, Is.EqualTo(2)); s.SetReadOnly(parent, true); s.SetReadOnly(child, true); s.Delete(parent); From 9cf5946414a0012f28faf9fefb1e27f4d5e827af Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 12 Jul 2023 06:30:30 +0000 Subject: [PATCH 10/14] Generate async files --- src/NHibernate.Test/Async/ReadOnly/ReadOnlyVersionedNodes.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/NHibernate.Test/Async/ReadOnly/ReadOnlyVersionedNodes.cs b/src/NHibernate.Test/Async/ReadOnly/ReadOnlyVersionedNodes.cs index 34732b41d40..2adb9224758 100644 --- a/src/NHibernate.Test/Async/ReadOnly/ReadOnlyVersionedNodes.cs +++ b/src/NHibernate.Test/Async/ReadOnly/ReadOnlyVersionedNodes.cs @@ -571,7 +571,7 @@ public async Task MergeDetachedChildWithNewParentCommitWithReadOnlyChildAsync() Assert.That(child.Version, Is.EqualTo(1)); Assert.That(parent, Is.Not.Null); Assert.That(parent.Children.Count, Is.EqualTo(0)); - Assert.That(parent.Version, Is.EqualTo(1)); + Assert.That(parent.Version, Is.EqualTo(2)); s.SetReadOnly(parent, true); s.SetReadOnly(child, true); await (s.DeleteAsync(parent)); @@ -622,8 +622,7 @@ public async Task GetChildMakeReadOnlyThenMergeDetachedChildWithNewParentAsync() Assert.That(child.Version, Is.EqualTo(1)); Assert.That(parent, Is.Not.Null); Assert.That(parent.Children.Count, Is.EqualTo(0)); - Assert.That(parent.Version, Is.EqualTo(1)); - // NH-specific: Hibernate incorrectly increments version number, NH does not + Assert.That(parent.Version, Is.EqualTo(2)); s.SetReadOnly(parent, true); s.SetReadOnly(child, true); await (s.DeleteAsync(parent)); From 593f3fe66c51075c935f7b9461151b8ec6240064 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Thu, 13 Jul 2023 20:13:28 +0300 Subject: [PATCH 11/14] Use unwrapped collection to add/remove items --- src/NHibernate.Test/NHSpecificTest/GH3325/Fixture.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH3325/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3325/Fixture.cs index a0b6b1e5030..5150c5ea069 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3325/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3325/Fixture.cs @@ -6,14 +6,8 @@ namespace NHibernate.Test.NHSpecificTest.GH3325 [TestFixture] public class Fixture : BugTestCase { - protected override void OnSetUp() - { - Sfi.Statistics.IsStatisticsEnabled = true; - } - protected override void OnTearDown() { - Sfi.Statistics.IsStatisticsEnabled = false; using (var session = OpenSession()) using (var transaction = session.BeginTransaction()) { @@ -34,16 +28,16 @@ public void CanAddChildAfterFlush() { var parent = new Entity { Name = "Parent" }; var child = new ChildEntity { Name = "Child" }; - parent.Children.Add(child); + var parentChildren = parent.Children; + parentChildren.Add(child); session.Save(parent); - parent.Children.Remove(child); + parentChildren.Remove(child); parentId = parent.Id; childId = child.Id; t.Commit(); } using (var session = OpenSession()) - using (var _ = session.BeginTransaction()) { var parent = session.Get(parentId); Assert.That(parent, Is.Not.Null); From c3c2a3b748e50f0fdadb64f637a9f0c32712b149 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 13 Jul 2023 17:16:30 +0000 Subject: [PATCH 12/14] Generate async files --- .../Async/NHSpecificTest/GH3325/Fixture.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3325/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3325/Fixture.cs index 51c1a980fa4..93b58942f52 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH3325/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3325/Fixture.cs @@ -17,14 +17,8 @@ namespace NHibernate.Test.NHSpecificTest.GH3325 [TestFixture] public class FixtureAsync : BugTestCase { - protected override void OnSetUp() - { - Sfi.Statistics.IsStatisticsEnabled = true; - } - protected override void OnTearDown() { - Sfi.Statistics.IsStatisticsEnabled = false; using (var session = OpenSession()) using (var transaction = session.BeginTransaction()) { @@ -45,16 +39,16 @@ public async Task CanAddChildAfterFlushAsync() { var parent = new Entity { Name = "Parent" }; var child = new ChildEntity { Name = "Child" }; - parent.Children.Add(child); + var parentChildren = parent.Children; + parentChildren.Add(child); await (session.SaveAsync(parent)); - parent.Children.Remove(child); + parentChildren.Remove(child); parentId = parent.Id; childId = child.Id; await (t.CommitAsync()); } using (var session = OpenSession()) - using (var _ = session.BeginTransaction()) { var parent = await (session.GetAsync(parentId)); Assert.That(parent, Is.Not.Null); From ae069a8e47c7b64e023a6a6c6ff01aee7cdcb7f8 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Fri, 14 Jul 2023 13:32:39 +1000 Subject: [PATCH 13/14] Test for more behaviours --- .../NHSpecificTest/GH3325/Fixture.cs | 126 +++++++++++++----- 1 file changed, 92 insertions(+), 34 deletions(-) diff --git a/src/NHibernate.Test/NHSpecificTest/GH3325/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3325/Fixture.cs index 5150c5ea069..a0ba4123dac 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3325/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3325/Fixture.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using NUnit.Framework; namespace NHibernate.Test.NHSpecificTest.GH3325 @@ -8,44 +9,101 @@ public class Fixture : BugTestCase { protected override void OnTearDown() { - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - session.CreateQuery("delete from ChildEntity").ExecuteUpdate(); - session.CreateQuery("delete from System.Object").ExecuteUpdate(); - - transaction.Commit(); - } + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + session.CreateQuery("delete from ChildEntity").ExecuteUpdate(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public void CanRemoveChildAfterSave() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + parent.Children.Add(child); + session.Save(parent); + parent.Children.Remove(child); + var parentId = parent.Id; + var childId = child.Id; + t.Commit(); + + AssertParentIsChildless(parentId, childId); + } + + [Test] + public void CanRemoveChildFromUnwrappedCollectionAfterSave() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + var parentChildren = parent.Children; + parentChildren.Add(child); + session.Save(parent); + parentChildren.Remove(child); + var parentId = parent.Id; + var childId = child.Id; + t.Commit(); + + AssertParentIsChildless(parentId, childId); } [Test] - public void CanAddChildAfterFlush() + public void CanRemoveChildAfterSaveAndExplicitFlush() { - Guid parentId; - Guid childId; - using (var session = OpenSession()) - using (var t = session.BeginTransaction()) - { - var parent = new Entity { Name = "Parent" }; - var child = new ChildEntity { Name = "Child" }; - var parentChildren = parent.Children; - parentChildren.Add(child); - session.Save(parent); - parentChildren.Remove(child); - parentId = parent.Id; - childId = child.Id; - t.Commit(); - } - - using (var session = OpenSession()) - { - var parent = session.Get(parentId); - Assert.That(parent, Is.Not.Null); - Assert.That(parent.Children, Has.Count.EqualTo(0)); - - var child = session.Get(childId); - Assert.That(child, Is.Null); - } + using var session = OpenSession(); + using var t = session.BeginTransaction(); + + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + parent.Children.Add(child); + session.Save(parent); + session.Flush(); + parent.Children.Remove(child); + var parentId = parent.Id; + var childId = child.Id; + t.Commit(); + + AssertParentIsChildless(parentId, childId); + } + + [Test] + public void CanRemoveChildFromUnwrappedCollectionAfterSaveAndExplicitFlush() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + var parentChildren = parent.Children; + parentChildren.Add(child); + session.Save(parent); + session.Flush(); + parentChildren.Remove(child); + var parentId = parent.Id; + var childId = child.Id; + t.Commit(); + + AssertParentIsChildless(parentId, childId); + } + + private void AssertParentIsChildless(Guid parentId, Guid childId) + { + using var session = OpenSession(); + + var parent = session.Get(parentId); + Assert.That(parent, Is.Not.Null); + Assert.That(parent.Children, Has.Count.EqualTo(0)); + + var child = session.Get(childId); + Assert.That(child, Is.Null); } } } From 5cbe028b8510e220c885080ebf10cc0219e666b9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 14 Jul 2023 03:36:01 +0000 Subject: [PATCH 14/14] Generate async files --- .../Async/NHSpecificTest/GH3325/Fixture.cs | 127 +++++++++++++----- 1 file changed, 93 insertions(+), 34 deletions(-) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3325/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3325/Fixture.cs index 93b58942f52..da325b51328 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH3325/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3325/Fixture.cs @@ -9,54 +9,113 @@ using System; +using System.Collections.Generic; using NUnit.Framework; namespace NHibernate.Test.NHSpecificTest.GH3325 { using System.Threading.Tasks; + using System.Threading; [TestFixture] public class FixtureAsync : BugTestCase { protected override void OnTearDown() { - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - session.CreateQuery("delete from ChildEntity").ExecuteUpdate(); - session.CreateQuery("delete from System.Object").ExecuteUpdate(); - - transaction.Commit(); - } + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + session.CreateQuery("delete from ChildEntity").ExecuteUpdate(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public async Task CanRemoveChildAfterSaveAsync() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + parent.Children.Add(child); + await (session.SaveAsync(parent)); + parent.Children.Remove(child); + var parentId = parent.Id; + var childId = child.Id; + await (t.CommitAsync()); + + await (AssertParentIsChildlessAsync(parentId, childId)); + } + + [Test] + public async Task CanRemoveChildFromUnwrappedCollectionAfterSaveAsync() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + var parentChildren = parent.Children; + parentChildren.Add(child); + await (session.SaveAsync(parent)); + parentChildren.Remove(child); + var parentId = parent.Id; + var childId = child.Id; + await (t.CommitAsync()); + + await (AssertParentIsChildlessAsync(parentId, childId)); } [Test] - public async Task CanAddChildAfterFlushAsync() + public async Task CanRemoveChildAfterSaveAndExplicitFlushAsync() { - Guid parentId; - Guid childId; - using (var session = OpenSession()) - using (var t = session.BeginTransaction()) - { - var parent = new Entity { Name = "Parent" }; - var child = new ChildEntity { Name = "Child" }; - var parentChildren = parent.Children; - parentChildren.Add(child); - await (session.SaveAsync(parent)); - parentChildren.Remove(child); - parentId = parent.Id; - childId = child.Id; - await (t.CommitAsync()); - } - - using (var session = OpenSession()) - { - var parent = await (session.GetAsync(parentId)); - Assert.That(parent, Is.Not.Null); - Assert.That(parent.Children, Has.Count.EqualTo(0)); - - var child = await (session.GetAsync(childId)); - Assert.That(child, Is.Null); - } + using var session = OpenSession(); + using var t = session.BeginTransaction(); + + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + parent.Children.Add(child); + await (session.SaveAsync(parent)); + await (session.FlushAsync()); + parent.Children.Remove(child); + var parentId = parent.Id; + var childId = child.Id; + await (t.CommitAsync()); + + await (AssertParentIsChildlessAsync(parentId, childId)); + } + + [Test] + public async Task CanRemoveChildFromUnwrappedCollectionAfterSaveAndExplicitFlushAsync() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + var parentChildren = parent.Children; + parentChildren.Add(child); + await (session.SaveAsync(parent)); + await (session.FlushAsync()); + parentChildren.Remove(child); + var parentId = parent.Id; + var childId = child.Id; + await (t.CommitAsync()); + + await (AssertParentIsChildlessAsync(parentId, childId)); + } + + private async Task AssertParentIsChildlessAsync(Guid parentId, Guid childId, CancellationToken cancellationToken = default(CancellationToken)) + { + using var session = OpenSession(); + + var parent = await (session.GetAsync(parentId, cancellationToken)); + Assert.That(parent, Is.Not.Null); + Assert.That(parent.Children, Has.Count.EqualTo(0)); + + var child = await (session.GetAsync(childId, cancellationToken)); + Assert.That(child, Is.Null); } } }