Skip to content

Commit

Permalink
Fix issue that EntityUpdateAction increments version despite veto on…
Browse files Browse the repository at this point in the history
… update (#3199)

Fixes #3198
  • Loading branch information
chenhh021 committed Nov 17, 2022
1 parent 53d1de7 commit 0672320
Show file tree
Hide file tree
Showing 4 changed files with 251 additions and 14 deletions.
130 changes: 130 additions & 0 deletions src/NHibernate.Test/Async/NHSpecificTest/GH3198/FixtureByCode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by AsyncGenerator.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------


using System;
using System.Threading;
using System.Threading.Tasks;
using NHibernate.Cfg;
using NHibernate.Cfg.MappingSchema;
using NHibernate.Event;
using NHibernate.Mapping.ByCode;
using NHibernate.Type;
using NUnit.Framework;

namespace NHibernate.Test.NHSpecificTest.GH3198
{
[TestFixture]
public partial class ByCodeFixtureAsync : TestCaseMappingByCode
{
private const int EXAMPLE_ID_VALUE = 1;

protected override void Configure(Configuration configuration)
{
// A listener always returning true
configuration.EventListeners.PreUpdateEventListeners = new IPreUpdateEventListener[]
{
new TestEventListener()
};
base.Configure(configuration);
}

protected override HbmMapping GetMappings()
{
var mapper = new ModelMapper();
mapper.Class<Entity>(rc =>
{
rc.Table("Entity");
rc.Id(x => x.Id, m => m.Generator(Generators.Assigned));
rc.Property(x => x.Name, x => x.Type<StringType>());
rc.Version(x => x.Version, vm => { });
});

return mapper.CompileMappingForAllExplicitlyAddedEntities();
}

protected override void OnSetUp()
{
using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
var e1 = new Entity { Id = EXAMPLE_ID_VALUE, Name = "old_name" };
session.Save(e1);
transaction.Commit();
}
}

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 TestVersionNotChangedWhenPreUpdateEventVetodAsync()
{
using (var session = OpenSession())
{
var entity = await (session.LoadAsync<Entity>(EXAMPLE_ID_VALUE));

entity.Name = "new_name";
await (session.UpdateAsync(entity));

var versionBeforeFlush = entity.Version;

await (session.FlushAsync());

var versionAfterflush = entity.Version;

Assert.That(versionAfterflush, Is.EqualTo(versionBeforeFlush), "The entity version must not change when update is vetoed");
}
}

// A listener always returning true
public partial class TestEventListener : IPreUpdateEventListener
{
public bool Executed { get; set; }
public bool FoundAny { get; set; }

public Task<bool> OnPreUpdateAsync(PreUpdateEvent @event, CancellationToken cancellationToken)
{
return Task.FromResult<bool>(true);
}

public bool OnPreUpdate(PreUpdateEvent @event)
{
return true;
}
}

public partial class Entity
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual int Version { get; set; }
}
}
public partial class ByCodeFixture : TestCaseMappingByCode
{

public partial class TestEventListener : IPreUpdateEventListener
{

public Task<bool> OnPreUpdateAsync(PreUpdateEvent @event, CancellationToken cancellationToken)
{
return Task.FromResult<bool>(true);
}
}
}
}
103 changes: 103 additions & 0 deletions src/NHibernate.Test/NHSpecificTest/GH3198/FixtureByCode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using NHibernate.Cfg;
using NHibernate.Cfg.MappingSchema;
using NHibernate.Event;
using NHibernate.Mapping.ByCode;
using NHibernate.Type;
using NUnit.Framework;

namespace NHibernate.Test.NHSpecificTest.GH3198
{
[TestFixture]
public partial class ByCodeFixture : TestCaseMappingByCode
{
private const int EXAMPLE_ID_VALUE = 1;

protected override void Configure(Configuration configuration)
{
// A listener always returning true
configuration.EventListeners.PreUpdateEventListeners = new IPreUpdateEventListener[]
{
new TestEventListener()
};
base.Configure(configuration);
}

protected override HbmMapping GetMappings()
{
var mapper = new ModelMapper();
mapper.Class<Entity>(rc =>
{
rc.Table("Entity");
rc.Id(x => x.Id, m => m.Generator(Generators.Assigned));
rc.Property(x => x.Name, x => x.Type<StringType>());
rc.Version(x => x.Version, vm => { });
});

return mapper.CompileMappingForAllExplicitlyAddedEntities();
}

protected override void OnSetUp()
{
using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
var e1 = new Entity { Id = EXAMPLE_ID_VALUE, Name = "old_name" };
session.Save(e1);
transaction.Commit();
}
}

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 TestVersionNotChangedWhenPreUpdateEventVetod()
{
using (var session = OpenSession())
{
var entity = session.Load<Entity>(EXAMPLE_ID_VALUE);

entity.Name = "new_name";
session.Update(entity);

var versionBeforeFlush = entity.Version;

session.Flush();

var versionAfterflush = entity.Version;

Assert.That(versionAfterflush, Is.EqualTo(versionBeforeFlush), "The entity version must not change when update is vetoed");
}
}

// A listener always returning true
public partial class TestEventListener : IPreUpdateEventListener
{
public bool Executed { get; set; }
public bool FoundAny { get; set; }

public bool OnPreUpdate(PreUpdateEvent @event)
{
return true;
}
}

public partial class Entity
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual int Version { get; set; }
}
}
}
16 changes: 9 additions & 7 deletions src/NHibernate/Action/EntityUpdateAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,11 @@ public override void Execute()
{
stopwatch = Stopwatch.StartNew();
}

bool veto = PreUpdate();

if (PreUpdate())
{
return;
}

ISessionFactoryImplementor factory = Session.Factory;

Expand All @@ -74,10 +77,9 @@ public override void Execute()
slock = persister.Cache.Lock(ck, previousVersion);
}

if (!veto)
{
persister.Update(id, state, dirtyFields, hasDirtyCollection, previousState, previousVersion, instance, null, session);
}

persister.Update(id, state, dirtyFields, hasDirtyCollection, previousState, previousVersion, instance, null, session);


EntityEntry entry = Session.PersistenceContext.GetEntry(instance);
if (entry == null)
Expand Down Expand Up @@ -128,7 +130,7 @@ public override void Execute()

PostUpdate();

if (statsEnabled && !veto)
if (statsEnabled)
{
stopwatch.Stop();
factory.StatisticsImplementor.UpdateEntity(Persister.EntityName, stopwatch.Elapsed);
Expand Down
16 changes: 9 additions & 7 deletions src/NHibernate/Async/Action/EntityUpdateAction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,11 @@ public override async Task ExecuteAsync(CancellationToken cancellationToken)
{
stopwatch = Stopwatch.StartNew();
}

bool veto = await (PreUpdateAsync(cancellationToken)).ConfigureAwait(false);

if (await (PreUpdateAsync(cancellationToken)).ConfigureAwait(false))
{
return;
}

ISessionFactoryImplementor factory = Session.Factory;

Expand All @@ -59,10 +62,9 @@ public override async Task ExecuteAsync(CancellationToken cancellationToken)
slock = await (persister.Cache.LockAsync(ck, previousVersion, cancellationToken)).ConfigureAwait(false);
}

if (!veto)
{
await (persister.UpdateAsync(id, state, dirtyFields, hasDirtyCollection, previousState, previousVersion, instance, null, session, cancellationToken)).ConfigureAwait(false);
}

await (persister.UpdateAsync(id, state, dirtyFields, hasDirtyCollection, previousState, previousVersion, instance, null, session, cancellationToken)).ConfigureAwait(false);


EntityEntry entry = Session.PersistenceContext.GetEntry(instance);
if (entry == null)
Expand Down Expand Up @@ -113,7 +115,7 @@ public override async Task ExecuteAsync(CancellationToken cancellationToken)

await (PostUpdateAsync(cancellationToken)).ConfigureAwait(false);

if (statsEnabled && !veto)
if (statsEnabled)
{
stopwatch.Stop();
factory.StatisticsImplementor.UpdateEntity(Persister.EntityName, stopwatch.Elapsed);
Expand Down

0 comments on commit 0672320

Please sign in to comment.