From adfa127a08a4be9dec5ef9ce949bbed0db7aa2ca Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Wed, 17 Nov 2021 14:08:50 +0200 Subject: [PATCH 1/2] Fix Refresh and Load event listeners for entity proxy --- .../NHSpecificTest/GH2727/FixtureByCode.cs | 97 +++++++++++++++++++ .../NHSpecificTest/GH2727/Entity.cs | 11 +++ .../NHSpecificTest/GH2727/FixtureByCode.cs | 86 ++++++++++++++++ .../Event/Default/DefaultLoadEventListener.cs | 4 +- .../Default/DefaultRefreshEventListener.cs | 2 +- .../Event/Default/DefaultLoadEventListener.cs | 4 +- .../Default/DefaultRefreshEventListener.cs | 2 +- 7 files changed, 200 insertions(+), 6 deletions(-) create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/GH2727/FixtureByCode.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH2727/Entity.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH2727/FixtureByCode.cs diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH2727/FixtureByCode.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH2727/FixtureByCode.cs new file mode 100644 index 00000000000..b7331f0f382 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH2727/FixtureByCode.cs @@ -0,0 +1,97 @@ +//------------------------------------------------------------------------------ +// +// 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 NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH2727 +{ + using System.Threading.Tasks; + /// + /// Fixture using 'by code' mappings + /// + [TestFixture] + public class LazyPropByCodeFixtureAsync : TestCaseMappingByCode + { + private Guid id1; + private Guid id2; + + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + mapper.Class( + rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.Property(x => x.Name); + rc.Property(x => x.LazyProp, m => m.Lazy(true)); + }); + + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + + protected override void OnSetUp() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var e1 = new Entity { Name = "Bob" }; + session.Save(e1); + + var e2 = new Entity { Name = "Sally" }; + session.Save(e2); + + transaction.Commit(); + id1 = e1.Id; + id2 = e2.Id; + } + } + + protected override void OnTearDown() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + // The HQL delete does all the job inside the database without loading the entities, but it does + // not handle delete order for avoiding violating constraints if any. Use + // session.Delete("from System.Object"); + // instead if in need of having NHbernate ordering the deletes, but this will cause + // loading the entities in the session. + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + } + + [Test] + public async Task CanLoadUsingInstanceAsync() + { + using (var s = OpenSession()) + { + var e1 = await (s.LoadAsync(id1)); + await (s.LoadAsync(e1, id2)); + } + } + + [Test(Description = "GH-2928")] + public async Task CanSessionRefreshEntityWithLazyPropertiesAsync() + { + using (var s = OpenSession()) + { + var e1 = await (s.GetAsync(id1)); + await (s.RefreshAsync(e1)); + s.Clear(); + await (s.RefreshAsync(e1)); + } + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH2727/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH2727/Entity.cs new file mode 100644 index 00000000000..5ef83cd5975 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH2727/Entity.cs @@ -0,0 +1,11 @@ +using System; + +namespace NHibernate.Test.NHSpecificTest.GH2727 +{ + public class Entity + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + public virtual string LazyProp { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH2727/FixtureByCode.cs b/src/NHibernate.Test/NHSpecificTest/GH2727/FixtureByCode.cs new file mode 100644 index 00000000000..3bd90a97f6e --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH2727/FixtureByCode.cs @@ -0,0 +1,86 @@ +using System; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH2727 +{ + /// + /// Fixture using 'by code' mappings + /// + [TestFixture] + public class LazyPropByCodeFixture : TestCaseMappingByCode + { + private Guid id1; + private Guid id2; + + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + mapper.Class( + rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.Property(x => x.Name); + rc.Property(x => x.LazyProp, m => m.Lazy(true)); + }); + + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + + protected override void OnSetUp() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var e1 = new Entity { Name = "Bob" }; + session.Save(e1); + + var e2 = new Entity { Name = "Sally" }; + session.Save(e2); + + transaction.Commit(); + id1 = e1.Id; + id2 = e2.Id; + } + } + + protected override void OnTearDown() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + // The HQL delete does all the job inside the database without loading the entities, but it does + // not handle delete order for avoiding violating constraints if any. Use + // session.Delete("from System.Object"); + // instead if in need of having NHbernate ordering the deletes, but this will cause + // loading the entities in the session. + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + } + + [Test] + public void CanLoadUsingInstance() + { + using (var s = OpenSession()) + { + var e1 = s.Load(id1); + s.Load(e1, id2); + } + } + + [Test(Description = "GH-2928")] + public void CanSessionRefreshEntityWithLazyProperties() + { + using (var s = OpenSession()) + { + var e1 = s.Get(id1); + s.Refresh(e1); + s.Clear(); + s.Refresh(e1); + } + } + } +} diff --git a/src/NHibernate/Async/Event/Default/DefaultLoadEventListener.cs b/src/NHibernate/Async/Event/Default/DefaultLoadEventListener.cs index e71e91aee2b..8d6a0a2d6d8 100644 --- a/src/NHibernate/Async/Event/Default/DefaultLoadEventListener.cs +++ b/src/NHibernate/Async/Event/Default/DefaultLoadEventListener.cs @@ -37,8 +37,8 @@ public virtual async Task OnLoadAsync(LoadEvent @event, LoadType loadType, Cance IEntityPersister persister; if (@event.InstanceToLoad != null) { - persister = source.GetEntityPersister(null, @event.InstanceToLoad); //the load() which takes an entity does not pass an entityName - @event.EntityClassName = @event.InstanceToLoad.GetType().FullName; + @event.EntityClassName = source.BestGuessEntityName(@event.InstanceToLoad);//the load() which takes an entity does not pass an entityName + persister = source.GetEntityPersister(@event.EntityClassName, @event.InstanceToLoad); } else { diff --git a/src/NHibernate/Async/Event/Default/DefaultRefreshEventListener.cs b/src/NHibernate/Async/Event/Default/DefaultRefreshEventListener.cs index 7d745ec2fa3..080c96a70b6 100644 --- a/src/NHibernate/Async/Event/Default/DefaultRefreshEventListener.cs +++ b/src/NHibernate/Async/Event/Default/DefaultRefreshEventListener.cs @@ -68,7 +68,7 @@ public virtual async Task OnRefreshAsync(RefreshEvent @event, IDictionary refres if (e == null) { - persister = source.GetEntityPersister(null, obj); //refresh() does not pass an entityName + persister = source.GetEntityPersister(source.BestGuessEntityName(obj), obj); //refresh() does not pass an entityName id = persister.GetIdentifier(obj); if (log.IsDebugEnabled()) { diff --git a/src/NHibernate/Event/Default/DefaultLoadEventListener.cs b/src/NHibernate/Event/Default/DefaultLoadEventListener.cs index 644cf67d1d1..dbfd0281cc2 100644 --- a/src/NHibernate/Event/Default/DefaultLoadEventListener.cs +++ b/src/NHibernate/Event/Default/DefaultLoadEventListener.cs @@ -33,8 +33,8 @@ public virtual void OnLoad(LoadEvent @event, LoadType loadType) IEntityPersister persister; if (@event.InstanceToLoad != null) { - persister = source.GetEntityPersister(null, @event.InstanceToLoad); //the load() which takes an entity does not pass an entityName - @event.EntityClassName = @event.InstanceToLoad.GetType().FullName; + @event.EntityClassName = source.BestGuessEntityName(@event.InstanceToLoad);//the load() which takes an entity does not pass an entityName + persister = source.GetEntityPersister(@event.EntityClassName, @event.InstanceToLoad); } else { diff --git a/src/NHibernate/Event/Default/DefaultRefreshEventListener.cs b/src/NHibernate/Event/Default/DefaultRefreshEventListener.cs index 4c04c066859..351fae84db9 100644 --- a/src/NHibernate/Event/Default/DefaultRefreshEventListener.cs +++ b/src/NHibernate/Event/Default/DefaultRefreshEventListener.cs @@ -50,7 +50,7 @@ public virtual void OnRefresh(RefreshEvent @event, IDictionary refreshedAlready) if (e == null) { - persister = source.GetEntityPersister(null, obj); //refresh() does not pass an entityName + persister = source.GetEntityPersister(source.BestGuessEntityName(obj), obj); //refresh() does not pass an entityName id = persister.GetIdentifier(obj); if (log.IsDebugEnabled()) { From bb1183ee1bee250967a29c1e65e75d89e99a7d61 Mon Sep 17 00:00:00 2001 From: Roman Artiukhin Date: Thu, 25 Nov 2021 14:33:15 +0200 Subject: [PATCH 2/2] whites --- src/NHibernate/Async/Event/Default/DefaultLoadEventListener.cs | 2 +- src/NHibernate/Event/Default/DefaultLoadEventListener.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NHibernate/Async/Event/Default/DefaultLoadEventListener.cs b/src/NHibernate/Async/Event/Default/DefaultLoadEventListener.cs index 8d6a0a2d6d8..2ec0cf0bd1e 100644 --- a/src/NHibernate/Async/Event/Default/DefaultLoadEventListener.cs +++ b/src/NHibernate/Async/Event/Default/DefaultLoadEventListener.cs @@ -37,7 +37,7 @@ public virtual async Task OnLoadAsync(LoadEvent @event, LoadType loadType, Cance IEntityPersister persister; if (@event.InstanceToLoad != null) { - @event.EntityClassName = source.BestGuessEntityName(@event.InstanceToLoad);//the load() which takes an entity does not pass an entityName + @event.EntityClassName = source.BestGuessEntityName(@event.InstanceToLoad); //the load() which takes an entity does not pass an entityName persister = source.GetEntityPersister(@event.EntityClassName, @event.InstanceToLoad); } else diff --git a/src/NHibernate/Event/Default/DefaultLoadEventListener.cs b/src/NHibernate/Event/Default/DefaultLoadEventListener.cs index dbfd0281cc2..df7f0287d04 100644 --- a/src/NHibernate/Event/Default/DefaultLoadEventListener.cs +++ b/src/NHibernate/Event/Default/DefaultLoadEventListener.cs @@ -33,7 +33,7 @@ public virtual void OnLoad(LoadEvent @event, LoadType loadType) IEntityPersister persister; if (@event.InstanceToLoad != null) { - @event.EntityClassName = source.BestGuessEntityName(@event.InstanceToLoad);//the load() which takes an entity does not pass an entityName + @event.EntityClassName = source.BestGuessEntityName(@event.InstanceToLoad); //the load() which takes an entity does not pass an entityName persister = source.GetEntityPersister(@event.EntityClassName, @event.InstanceToLoad); } else