From ca40016827e30de594a874326999078d51a7ce3c Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Sat, 5 Feb 2022 18:56:45 +0200 Subject: [PATCH 1/6] Fix optional join optimistic lock handling --- .../GH1235/OptionalJoinFixture.cs | 196 ++++++++++++++++++ .../NHSpecificTest/GH1235/Entity.cs | 12 ++ .../GH1235/OptionalJoinFixture.cs | 184 ++++++++++++++++ .../Entity/AbstractEntityPersister.cs | 6 +- .../Entity/AbstractEntityPersister.cs | 22 +- 5 files changed, 412 insertions(+), 8 deletions(-) create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/GH1235/OptionalJoinFixture.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH1235/Entity.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH1235/OptionalJoinFixture.cs diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH1235/OptionalJoinFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH1235/OptionalJoinFixture.cs new file mode 100644 index 00000000000..9ba97d440b0 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH1235/OptionalJoinFixture.cs @@ -0,0 +1,196 @@ +//------------------------------------------------------------------------------ +// +// 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.Linq; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NUnit.Framework; +using NUnit.Framework.Constraints; +using NHibernate.Linq; + +namespace NHibernate.Test.NHSpecificTest.GH1235 +{ + using System.Threading.Tasks; + //NH-2785 + [TestFixture(true, "OptimisticLock")] + [TestFixture(false, "Version")] + [TestFixture(null, "NotVersioned")] + public class OptionalJoinFixtureAsync : TestCaseMappingByCode + { + private readonly bool? _optimisticLock; + + public OptionalJoinFixtureAsync(bool? optimisticLock, string comment) + { + _optimisticLock = optimisticLock; + } + + protected override void OnTearDown() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + } + + [Test] + public async Task UpdateNullOptionalJoinToNotNullAsync() + { + object id; + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = new MultiTableEntity { Name = "Bob" }; + id = await (s.SaveAsync(entity)); + await (t.CommitAsync()); + } + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var e = await (s.GetAsync(id)); + e.OtherName = "Sally"; + await (t.CommitAsync()); + } + + using (var s = OpenSession()) + { + var e = await (s.GetAsync(id)); + Assert.That(e.OtherName, Is.EqualTo("Sally")); + } + } + + [Test] + public async Task UpdateNullOptionalJoinToNotNullDetachedAsync() + { + object id; + MultiTableEntity entity; + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + entity = new MultiTableEntity { Name = "Bob" }; + id = await (s.SaveAsync(entity)); + await (t.CommitAsync()); + } + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + entity.OtherName = "Sally"; + await (s.UpdateAsync(entity)); + await (t.CommitAsync()); + } + + using (var s = OpenSession()) + { + var e = await (s.GetAsync(id)); + Assert.That(e.OtherName, Is.EqualTo("Sally")); + } + } + + [Test] + public async Task ShouldThrowStaleStateForOptimisticLockUpdateAsync() + { + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + + { + var result = new MultiTableEntity { Name = "Bob", OtherName = "Bob" }; + await (s.SaveAsync(result)); + await (t.CommitAsync()); + } + + using (var s1 = OpenSession()) + using (var t1 = s1.BeginTransaction()) + { + var result = await (s1.Query().FirstOrDefaultAsync()); + + result.OtherName += "x"; + using (var s2 = OpenSession()) + using (var t2 = s2.BeginTransaction()) + { + var result2 = await (s2.Query().FirstOrDefaultAsync()); + result2.OtherName += "y"; + await (t1.CommitAsync()); + Assert.That( + () => t2.CommitAsync(), + _optimisticLock == null + ? (IResolveConstraint) Throws.Nothing + : Throws.InstanceOf()); + } + } + } + + [Test] + public async Task ShouldThrowStaleStateForOptimisticLockDeleteAsync() + { + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + + { + var result = new MultiTableEntity { Name = "Bob", OtherName = "Bob" }; + await (s.SaveAsync(result)); + await (t.CommitAsync()); + } + + using (var s1 = OpenSession()) + using (var t1 = s1.BeginTransaction()) + { + var result = await (s1.Query().FirstOrDefaultAsync()); + + result.OtherName += "x"; + using (var s2 = OpenSession()) + using (var t2 = s2.BeginTransaction()) + { + var result2 = await (s2.Query().FirstOrDefaultAsync()); + await (s2.DeleteAsync(result2)); + await (t1.CommitAsync()); + Assert.That( + () => t2.CommitAsync(), + _optimisticLock == null + ? (IResolveConstraint) Throws.Nothing + : Throws.InstanceOf()); + } + } + } + + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + mapper.Class( + rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.Native)); + rc.DynamicUpdate(true); + + if (_optimisticLock == true) + rc.OptimisticLock(OptimisticLockMode.Dirty); + else if (_optimisticLock != null) + rc.Version(x => x.Version, _ => { }); + + rc.Property(x => x.Name); + rc.Join( + "SecondTable", + m => + { + m.Key(k => k.Column("Id")); + m.Property(x => x.OtherName); + m.Optional(true); + }); + }); + + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH1235/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH1235/Entity.cs new file mode 100644 index 00000000000..feda2775d84 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH1235/Entity.cs @@ -0,0 +1,12 @@ +using System; + +namespace NHibernate.Test.NHSpecificTest.GH1235 +{ + class MultiTableEntity + { + public virtual int Id { get; set; } + public virtual int Version { get; set; } + public virtual string Name { get; set; } + public virtual string OtherName { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH1235/OptionalJoinFixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1235/OptionalJoinFixture.cs new file mode 100644 index 00000000000..52337365993 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH1235/OptionalJoinFixture.cs @@ -0,0 +1,184 @@ +using System.Linq; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NUnit.Framework; +using NUnit.Framework.Constraints; + +namespace NHibernate.Test.NHSpecificTest.GH1235 +{ + //NH-2785 + [TestFixture(true, "OptimisticLock")] + [TestFixture(false, "Version")] + [TestFixture(null, "NotVersioned")] + public class OptionalJoinFixture : TestCaseMappingByCode + { + private readonly bool? _optimisticLock; + + public OptionalJoinFixture(bool? optimisticLock, string comment) + { + _optimisticLock = optimisticLock; + } + + protected override void OnTearDown() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + } + + [Test] + public void UpdateNullOptionalJoinToNotNull() + { + object id; + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = new MultiTableEntity { Name = "Bob" }; + id = s.Save(entity); + t.Commit(); + } + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var e = s.Get(id); + e.OtherName = "Sally"; + t.Commit(); + } + + using (var s = OpenSession()) + { + var e = s.Get(id); + Assert.That(e.OtherName, Is.EqualTo("Sally")); + } + } + + [Test] + public void UpdateNullOptionalJoinToNotNullDetached() + { + object id; + MultiTableEntity entity; + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + entity = new MultiTableEntity { Name = "Bob" }; + id = s.Save(entity); + t.Commit(); + } + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + entity.OtherName = "Sally"; + s.Update(entity); + t.Commit(); + } + + using (var s = OpenSession()) + { + var e = s.Get(id); + Assert.That(e.OtherName, Is.EqualTo("Sally")); + } + } + + [Test] + public void ShouldThrowStaleStateForOptimisticLockUpdate() + { + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + + { + var result = new MultiTableEntity { Name = "Bob", OtherName = "Bob" }; + s.Save(result); + t.Commit(); + } + + using (var s1 = OpenSession()) + using (var t1 = s1.BeginTransaction()) + { + var result = s1.Query().FirstOrDefault(); + + result.OtherName += "x"; + using (var s2 = OpenSession()) + using (var t2 = s2.BeginTransaction()) + { + var result2 = s2.Query().FirstOrDefault(); + result2.OtherName += "y"; + t1.Commit(); + Assert.That( + () => t2.Commit(), + _optimisticLock == null + ? (IResolveConstraint) Throws.Nothing + : Throws.InstanceOf()); + } + } + } + + [Test] + public void ShouldThrowStaleStateForOptimisticLockDelete() + { + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + + { + var result = new MultiTableEntity { Name = "Bob", OtherName = "Bob" }; + s.Save(result); + t.Commit(); + } + + using (var s1 = OpenSession()) + using (var t1 = s1.BeginTransaction()) + { + var result = s1.Query().FirstOrDefault(); + + result.OtherName += "x"; + using (var s2 = OpenSession()) + using (var t2 = s2.BeginTransaction()) + { + var result2 = s2.Query().FirstOrDefault(); + s2.Delete(result2); + t1.Commit(); + Assert.That( + () => t2.Commit(), + _optimisticLock == null + ? (IResolveConstraint) Throws.Nothing + : Throws.InstanceOf()); + } + } + } + + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + mapper.Class( + rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.Native)); + rc.DynamicUpdate(true); + + if (_optimisticLock == true) + rc.OptimisticLock(OptimisticLockMode.Dirty); + else if (_optimisticLock != null) + rc.Version(x => x.Version, _ => { }); + + rc.Property(x => x.Name); + rc.Join( + "SecondTable", + m => + { + m.Key(k => k.Column("Id")); + m.Property(x => x.OtherName); + m.Optional(true); + }); + }); + + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + } +} diff --git a/src/NHibernate/Async/Persister/Entity/AbstractEntityPersister.cs b/src/NHibernate/Async/Persister/Entity/AbstractEntityPersister.cs index d5005ea10af..3802fbe0c42 100644 --- a/src/NHibernate/Async/Persister/Entity/AbstractEntityPersister.cs +++ b/src/NHibernate/Async/Persister/Entity/AbstractEntityPersister.cs @@ -785,7 +785,7 @@ protected async Task UpdateAsync(object id, object[] fields, object[] oldF } else { - return Check(await (session.Batcher.ExecuteNonQueryAsync(statement, cancellationToken)).ConfigureAwait(false), id, j, expectation, statement); + return Check(await (session.Batcher.ExecuteNonQueryAsync(statement, cancellationToken)).ConfigureAwait(false), id, j, expectation, statement, IsPropertyBasedOptimisticLocking(oldFields)); } } catch (OperationCanceledException) { throw; } @@ -891,7 +891,7 @@ public async Task DeleteAsync(object id, object version, int j, object obj, SqlC { await (VersionType.NullSafeSetAsync(statement, version, index, session, cancellationToken)).ConfigureAwait(false); } - else if (entityMetamodel.OptimisticLockMode > Versioning.OptimisticLock.Version && loadedState != null) + else if (IsPropertyBasedOptimisticLocking(loadedState)) { bool[] versionability = PropertyVersionability; IType[] types = PropertyTypes; @@ -915,7 +915,7 @@ public async Task DeleteAsync(object id, object version, int j, object obj, SqlC } else { - Check(await (session.Batcher.ExecuteNonQueryAsync(statement, cancellationToken)).ConfigureAwait(false), tableId, j, expectation, statement); + Check(await (session.Batcher.ExecuteNonQueryAsync(statement, cancellationToken)).ConfigureAwait(false), tableId, j, expectation, statement, IsPropertyBasedOptimisticLocking(loadedState)); } } catch (OperationCanceledException) { throw; } diff --git a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs index 409808945c9..7c44f409057 100644 --- a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs +++ b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs @@ -2517,6 +2517,11 @@ protected IUniqueEntityLoader CreateEntityLoader(LockMode lockMode) } protected bool Check(int rows, object id, int tableNumber, IExpectation expectation, DbCommand statement) + { + return Check(rows, id, tableNumber, expectation, statement, false); + } + + protected bool Check(int rows, object id, int tableNumber, IExpectation expectation, DbCommand statement, bool forceThrowStaleException = false) { try { @@ -2524,13 +2529,15 @@ protected bool Check(int rows, object id, int tableNumber, IExpectation expectat } catch (StaleStateException sse) { - if (!IsNullableTable(tableNumber)) + if (forceThrowStaleException || !IsNullableTable(tableNumber)) { if (Factory.Statistics.IsStatisticsEnabled) Factory.StatisticsImplementor.OptimisticFailure(EntityName); throw new StaleObjectStateException(EntityName, id, sse); } + + return false; } catch (TooManyRowsAffectedException ex) { @@ -2592,7 +2599,7 @@ protected internal SqlCommandInfo GenerateUpdateString(bool[] includeProperty, i hasColumns = true; } } - else if (entityMetamodel.OptimisticLockMode > Versioning.OptimisticLock.Version && oldFields != null) + else if (IsPropertyBasedOptimisticLocking(oldFields)) { // we are using "all" or "dirty" property-based optimistic locking bool[] includeInWhere = @@ -2636,6 +2643,11 @@ protected internal SqlCommandInfo GenerateUpdateString(bool[] includeProperty, i return hasColumns ? updateBuilder.ToSqlCommandInfo() : null; } + private bool IsPropertyBasedOptimisticLocking(object[] oldFields) + { + return entityMetamodel.OptimisticLockMode > Versioning.OptimisticLock.Version && oldFields != null; + } + private bool CheckVersion(bool[] includeProperty) { return includeProperty[VersionProperty] || entityMetamodel.PropertyUpdateGenerationInclusions[VersionProperty] != ValueInclusion.None; @@ -3248,7 +3260,7 @@ protected bool Update(object id, object[] fields, object[] oldFields, object row } else { - return Check(session.Batcher.ExecuteNonQuery(statement), id, j, expectation, statement); + return Check(session.Batcher.ExecuteNonQuery(statement), id, j, expectation, statement, IsPropertyBasedOptimisticLocking(oldFields)); } } catch (StaleStateException e) @@ -3352,7 +3364,7 @@ public void Delete(object id, object version, int j, object obj, SqlCommandInfo { VersionType.NullSafeSet(statement, version, index, session); } - else if (entityMetamodel.OptimisticLockMode > Versioning.OptimisticLock.Version && loadedState != null) + else if (IsPropertyBasedOptimisticLocking(loadedState)) { bool[] versionability = PropertyVersionability; IType[] types = PropertyTypes; @@ -3376,7 +3388,7 @@ public void Delete(object id, object version, int j, object obj, SqlCommandInfo } else { - Check(session.Batcher.ExecuteNonQuery(statement), tableId, j, expectation, statement); + Check(session.Batcher.ExecuteNonQuery(statement), tableId, j, expectation, statement, IsPropertyBasedOptimisticLocking(loadedState)); } } catch (Exception e) From 2b4077e440411899ef14bb1c99e643c2eb643a23 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Sat, 5 Feb 2022 19:26:13 +0200 Subject: [PATCH 2/6] Make test SQLite friendly --- .../Async/NHSpecificTest/GH1235/OptionalJoinFixture.cs | 6 ++++-- .../NHSpecificTest/GH1235/OptionalJoinFixture.cs | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH1235/OptionalJoinFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH1235/OptionalJoinFixture.cs index 9ba97d440b0..1173fc8bdae 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH1235/OptionalJoinFixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH1235/OptionalJoinFixture.cs @@ -118,11 +118,12 @@ public async Task ShouldThrowStaleStateForOptimisticLockUpdateAsync() result.OtherName += "x"; using (var s2 = OpenSession()) - using (var t2 = s2.BeginTransaction()) { var result2 = await (s2.Query().FirstOrDefaultAsync()); result2.OtherName += "y"; await (t1.CommitAsync()); + + using (var t2 = s2.BeginTransaction()) Assert.That( () => t2.CommitAsync(), _optimisticLock == null @@ -151,11 +152,12 @@ public async Task ShouldThrowStaleStateForOptimisticLockDeleteAsync() result.OtherName += "x"; using (var s2 = OpenSession()) - using (var t2 = s2.BeginTransaction()) { var result2 = await (s2.Query().FirstOrDefaultAsync()); await (s2.DeleteAsync(result2)); await (t1.CommitAsync()); + + using (var t2 = s2.BeginTransaction()) Assert.That( () => t2.CommitAsync(), _optimisticLock == null diff --git a/src/NHibernate.Test/NHSpecificTest/GH1235/OptionalJoinFixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1235/OptionalJoinFixture.cs index 52337365993..26a25131d18 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1235/OptionalJoinFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1235/OptionalJoinFixture.cs @@ -106,11 +106,12 @@ public void ShouldThrowStaleStateForOptimisticLockUpdate() result.OtherName += "x"; using (var s2 = OpenSession()) - using (var t2 = s2.BeginTransaction()) { var result2 = s2.Query().FirstOrDefault(); result2.OtherName += "y"; t1.Commit(); + + using (var t2 = s2.BeginTransaction()) Assert.That( () => t2.Commit(), _optimisticLock == null @@ -139,11 +140,12 @@ public void ShouldThrowStaleStateForOptimisticLockDelete() result.OtherName += "x"; using (var s2 = OpenSession()) - using (var t2 = s2.BeginTransaction()) { var result2 = s2.Query().FirstOrDefault(); s2.Delete(result2); t1.Commit(); + + using (var t2 = s2.BeginTransaction()) Assert.That( () => t2.Commit(), _optimisticLock == null From 0c8f1209f57bf0829ceb1f8ff940f30a628b0c93 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Sat, 5 Feb 2022 21:36:57 +0200 Subject: [PATCH 3/6] Refactor test --- .../GH1235/OptionalJoinFixture.cs | 37 +++++++++---------- .../GH1235/OptionalJoinFixture.cs | 37 +++++++++---------- 2 files changed, 34 insertions(+), 40 deletions(-) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH1235/OptionalJoinFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH1235/OptionalJoinFixture.cs index 1173fc8bdae..8d6215b0678 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH1235/OptionalJoinFixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH1235/OptionalJoinFixture.cs @@ -19,14 +19,14 @@ namespace NHibernate.Test.NHSpecificTest.GH1235 { using System.Threading.Tasks; //NH-2785 - [TestFixture(true, "OptimisticLock")] - [TestFixture(false, "Version")] - [TestFixture(null, "NotVersioned")] + [TestFixture(OptimisticLockMode.None)] + [TestFixture(OptimisticLockMode.Version)] + [TestFixture(OptimisticLockMode.Dirty)] public class OptionalJoinFixtureAsync : TestCaseMappingByCode { - private readonly bool? _optimisticLock; + private readonly OptimisticLockMode _optimisticLock; - public OptionalJoinFixtureAsync(bool? optimisticLock, string comment) + public OptionalJoinFixtureAsync(OptimisticLockMode optimisticLock) { _optimisticLock = optimisticLock; } @@ -104,7 +104,6 @@ public async Task ShouldThrowStaleStateForOptimisticLockUpdateAsync() { using (var s = OpenSession()) using (var t = s.BeginTransaction()) - { var result = new MultiTableEntity { Name = "Bob", OtherName = "Bob" }; await (s.SaveAsync(result)); @@ -124,11 +123,11 @@ public async Task ShouldThrowStaleStateForOptimisticLockUpdateAsync() await (t1.CommitAsync()); using (var t2 = s2.BeginTransaction()) - Assert.That( - () => t2.CommitAsync(), - _optimisticLock == null - ? (IResolveConstraint) Throws.Nothing - : Throws.InstanceOf()); + Assert.That( + () => t2.CommitAsync(), + _optimisticLock == OptimisticLockMode.None + ? (IResolveConstraint) Throws.Nothing + : Throws.InstanceOf()); } } } @@ -138,7 +137,6 @@ public async Task ShouldThrowStaleStateForOptimisticLockDeleteAsync() { using (var s = OpenSession()) using (var t = s.BeginTransaction()) - { var result = new MultiTableEntity { Name = "Bob", OtherName = "Bob" }; await (s.SaveAsync(result)); @@ -158,11 +156,11 @@ public async Task ShouldThrowStaleStateForOptimisticLockDeleteAsync() await (t1.CommitAsync()); using (var t2 = s2.BeginTransaction()) - Assert.That( - () => t2.CommitAsync(), - _optimisticLock == null - ? (IResolveConstraint) Throws.Nothing - : Throws.InstanceOf()); + Assert.That( + () => t2.CommitAsync(), + _optimisticLock == OptimisticLockMode.None + ? (IResolveConstraint) Throws.Nothing + : Throws.InstanceOf()); } } } @@ -175,10 +173,9 @@ protected override HbmMapping GetMappings() { rc.Id(x => x.Id, m => m.Generator(Generators.Native)); rc.DynamicUpdate(true); + rc.OptimisticLock(_optimisticLock); - if (_optimisticLock == true) - rc.OptimisticLock(OptimisticLockMode.Dirty); - else if (_optimisticLock != null) + if (_optimisticLock == OptimisticLockMode.Version) rc.Version(x => x.Version, _ => { }); rc.Property(x => x.Name); diff --git a/src/NHibernate.Test/NHSpecificTest/GH1235/OptionalJoinFixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1235/OptionalJoinFixture.cs index 26a25131d18..6f35c80404a 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1235/OptionalJoinFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1235/OptionalJoinFixture.cs @@ -7,14 +7,14 @@ namespace NHibernate.Test.NHSpecificTest.GH1235 { //NH-2785 - [TestFixture(true, "OptimisticLock")] - [TestFixture(false, "Version")] - [TestFixture(null, "NotVersioned")] + [TestFixture(OptimisticLockMode.None)] + [TestFixture(OptimisticLockMode.Version)] + [TestFixture(OptimisticLockMode.Dirty)] public class OptionalJoinFixture : TestCaseMappingByCode { - private readonly bool? _optimisticLock; + private readonly OptimisticLockMode _optimisticLock; - public OptionalJoinFixture(bool? optimisticLock, string comment) + public OptionalJoinFixture(OptimisticLockMode optimisticLock) { _optimisticLock = optimisticLock; } @@ -92,7 +92,6 @@ public void ShouldThrowStaleStateForOptimisticLockUpdate() { using (var s = OpenSession()) using (var t = s.BeginTransaction()) - { var result = new MultiTableEntity { Name = "Bob", OtherName = "Bob" }; s.Save(result); @@ -112,11 +111,11 @@ public void ShouldThrowStaleStateForOptimisticLockUpdate() t1.Commit(); using (var t2 = s2.BeginTransaction()) - Assert.That( - () => t2.Commit(), - _optimisticLock == null - ? (IResolveConstraint) Throws.Nothing - : Throws.InstanceOf()); + Assert.That( + () => t2.Commit(), + _optimisticLock == OptimisticLockMode.None + ? (IResolveConstraint) Throws.Nothing + : Throws.InstanceOf()); } } } @@ -126,7 +125,6 @@ public void ShouldThrowStaleStateForOptimisticLockDelete() { using (var s = OpenSession()) using (var t = s.BeginTransaction()) - { var result = new MultiTableEntity { Name = "Bob", OtherName = "Bob" }; s.Save(result); @@ -146,11 +144,11 @@ public void ShouldThrowStaleStateForOptimisticLockDelete() t1.Commit(); using (var t2 = s2.BeginTransaction()) - Assert.That( - () => t2.Commit(), - _optimisticLock == null - ? (IResolveConstraint) Throws.Nothing - : Throws.InstanceOf()); + Assert.That( + () => t2.Commit(), + _optimisticLock == OptimisticLockMode.None + ? (IResolveConstraint) Throws.Nothing + : Throws.InstanceOf()); } } } @@ -163,10 +161,9 @@ protected override HbmMapping GetMappings() { rc.Id(x => x.Id, m => m.Generator(Generators.Native)); rc.DynamicUpdate(true); + rc.OptimisticLock(_optimisticLock); - if (_optimisticLock == true) - rc.OptimisticLock(OptimisticLockMode.Dirty); - else if (_optimisticLock != null) + if (_optimisticLock == OptimisticLockMode.Version) rc.Version(x => x.Version, _ => { }); rc.Property(x => x.Name); From a6f31c5440cd3c3821164b9d471077cf6efbafe5 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Sun, 6 Feb 2022 09:50:10 +0200 Subject: [PATCH 4/6] Fix SqlServerCe --- .../Async/NHSpecificTest/GH1235/OptionalJoinFixture.cs | 5 ++++- .../NHSpecificTest/GH1235/OptionalJoinFixture.cs | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH1235/OptionalJoinFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH1235/OptionalJoinFixture.cs index 8d6215b0678..5398f667d62 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH1235/OptionalJoinFixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH1235/OptionalJoinFixture.cs @@ -36,7 +36,10 @@ protected override void OnTearDown() using (var session = OpenSession()) using (var transaction = session.BeginTransaction()) { - session.CreateQuery("delete from System.Object").ExecuteUpdate(); + if (Dialect.SupportsTemporaryTables) + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + else + session.Delete("from System.Object"); transaction.Commit(); } diff --git a/src/NHibernate.Test/NHSpecificTest/GH1235/OptionalJoinFixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1235/OptionalJoinFixture.cs index 6f35c80404a..578c6ece59d 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1235/OptionalJoinFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1235/OptionalJoinFixture.cs @@ -24,7 +24,10 @@ protected override void OnTearDown() using (var session = OpenSession()) using (var transaction = session.BeginTransaction()) { - session.CreateQuery("delete from System.Object").ExecuteUpdate(); + if (Dialect.SupportsTemporaryTables) + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + else + session.Delete("from System.Object"); transaction.Commit(); } From f5699d88876a16e174be9609a1b52d8a7217882a Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Thu, 10 Feb 2022 07:52:16 +0200 Subject: [PATCH 5/6] Commented --- src/NHibernate/Persister/Entity/AbstractEntityPersister.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs index 7c44f409057..9e654fefb55 100644 --- a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs +++ b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs @@ -2516,6 +2516,7 @@ protected IUniqueEntityLoader CreateEntityLoader(LockMode lockMode) return CreateEntityLoader(lockMode, CollectionHelper.EmptyDictionary()); } + //TODO 6.0: Remove (replaced by overload with optional parameter) protected bool Check(int rows, object id, int tableNumber, IExpectation expectation, DbCommand statement) { return Check(rows, id, tableNumber, expectation, statement, false); From 72afd31d370f5458648ca23392a972eb8afe4488 Mon Sep 17 00:00:00 2001 From: Alex Zaytsev Date: Thu, 4 Aug 2022 17:34:15 +1200 Subject: [PATCH 6/6] Replace on one forgotten place --- .../Async/Persister/Entity/AbstractEntityPersister.cs | 2 +- src/NHibernate/Persister/Entity/AbstractEntityPersister.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NHibernate/Async/Persister/Entity/AbstractEntityPersister.cs b/src/NHibernate/Async/Persister/Entity/AbstractEntityPersister.cs index 3802fbe0c42..1e9ec77f2ba 100644 --- a/src/NHibernate/Async/Persister/Entity/AbstractEntityPersister.cs +++ b/src/NHibernate/Async/Persister/Entity/AbstractEntityPersister.cs @@ -756,7 +756,7 @@ protected async Task UpdateAsync(object id, object[] fields, object[] oldF if (CheckVersion(includeProperty)) await (VersionType.NullSafeSetAsync(statement, oldVersion, index, session, cancellationToken)).ConfigureAwait(false); } - else if (entityMetamodel.OptimisticLockMode > Versioning.OptimisticLock.Version && oldFields != null) + else if (IsPropertyBasedOptimisticLocking(oldFields)) { bool[] versionability = PropertyVersionability; bool[] includeOldField = OptimisticLockMode == Versioning.OptimisticLock.All diff --git a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs index 9e654fefb55..76732bb69f6 100644 --- a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs +++ b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs @@ -3232,7 +3232,7 @@ protected bool Update(object id, object[] fields, object[] oldFields, object row if (CheckVersion(includeProperty)) VersionType.NullSafeSet(statement, oldVersion, index, session); } - else if (entityMetamodel.OptimisticLockMode > Versioning.OptimisticLock.Version && oldFields != null) + else if (IsPropertyBasedOptimisticLocking(oldFields)) { bool[] versionability = PropertyVersionability; bool[] includeOldField = OptimisticLockMode == Versioning.OptimisticLock.All