Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating related entities of versioned entity increments version and triggers post update listener #3466

Open
Madajevas opened this issue Jan 4, 2024 · 0 comments

Comments

@Madajevas
Copy link

Hi. The following tests should illustrate my issue best:

using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using FluentNHibernate.Mapping;

using NHibernate;
using NHibernate.Event;

using NSubstitute;

namespace Tests
{
    public class WithVersion
    {
        private ISessionFactory sessionFactory;
        private IPostUpdateEventListener postUpdateListener;

        [SetUp]
        public void SetUp()
        {
            postUpdateListener = Substitute.For<IPostUpdateEventListener>();

            /*
            CREATE TABLE EntityWithVersion (
                Id bigint IDENTITY(1,1) NOT NULL PRIMARY KEY,
                Name varchar(100) NOT NULL,
                Version bigint not null
            )
            CREATE TABLE Others (
                Id int IDENTITY(1,1) NOT NULL PRIMARY KEY,
                Name varchar(100) NOT NULL,
                EntityId int NOT NULL
            )
            */
            var config = Fluently.Configure()
                .Database(MsSqlConfiguration.MsSql2008.ConnectionString("Server=localhost;Database=test;User Id=sa;Password=test;"))
                .Mappings(m => m.FluentMappings.Add<EntityWithVersionMap>().Add<OthersMap>())
                .ExposeConfiguration(c => c.AppendListeners(ListenerType.PostUpdate, new[] { postUpdateListener }))
                .BuildConfiguration();

            sessionFactory = config.BuildSessionFactory();
        }

        [Test, Explicit]
        public async Task CreateEntity()
        {
            using var session = sessionFactory.OpenSession();
            using var transaction = session.BeginTransaction();

            var entity = new EntityWithVersion { Name = "test" };
            entity.Others.Add(new Others { Name = "test" });
            await session.SaveAsync(entity);

            await transaction.CommitAsync();
        }

        [Test]
        public async Task ModifyingChildEntities_UpdatesVersion()
        {
            long originalVersion;
            using (var session = sessionFactory.OpenSession())
            using (var transaction = session.BeginTransaction())
            {
                var entity = await session.GetAsync<EntityWithVersion>(1);
                originalVersion = entity.Version;

                entity.Others.Clear();
                entity.Others.Add(session.Load<Others>(1));
                await session.SaveAsync(entity);

                await transaction.CommitAsync();
            }

            using var session2 = sessionFactory.OpenSession();
            var modifiedEntity = await session2.GetAsync<EntityWithVersion>(1);
            Assert.That(modifiedEntity.Version, Is.EqualTo(originalVersion));
        }

        [Test]
        public async Task ModifyingChildEntities_TriggersUpdateListener()
        {
            using (var session = sessionFactory.OpenSession())
            using (var transaction = session.BeginTransaction())
            {
                var entity = await session.GetAsync<EntityWithVersion>(1);
                entity.Others.Clear();
                entity.Others.Add(session.Load<Others>(1));
                await session.SaveAsync(entity);

                await transaction.CommitAsync();
            }

            await postUpdateListener.DidNotReceive().OnPostUpdateAsync(Arg.Any<PostUpdateEvent>(), Arg.Any<CancellationToken>());
        }
    }

    public class EntityWithVersion
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }

        public virtual ISet<Others> Others { get; set; } = new HashSet<Others>();

        public virtual long Version { get; set; }
    }

    class EntityWithVersionMap : ClassMap<EntityWithVersion>
    {
        public EntityWithVersionMap()
        {
            Id(e => e.Id).GeneratedBy.Identity();
            Map(e => e.Name);
            Version(e => e.Version);

            HasMany(e => e.Others)
                .Table("Others").Cascade.All()
                .KeyColumn("EntityId").Not.KeyNullable();
        }
    }

    public class Others
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
    }
    class OthersMap : ClassMap<Others>
    {
        public OthersMap()
        {
            Id(e => e.Id).GeneratedBy.Identity();
            Map(e => e.Name);
        }
    }
}

My questions are:

  1. Can I prevent version update if entity itself did not change?
  2. Can I prevent post update listeners from being called if only version field has changed (if version mapping is commented out, listener is not called).

Reproducible with version 5.4.2 and 5.5.0. Have not checked any other versions.

Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant