diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3643/FixtureByCode.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3643/FixtureByCode.cs new file mode 100644 index 0000000000..71b43faf92 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3643/FixtureByCode.cs @@ -0,0 +1,124 @@ +//------------------------------------------------------------------------------ +// +// 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; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Linq; +using NHibernate.Mapping.ByCode; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3643 +{ + using System.Threading.Tasks; + using System.Threading; + [TestFixture] + public class FixtureByCodeAsync : TestCaseMappingByCode + { + protected override void Configure(Configuration configuration) + { + configuration.SetProperty(Environment.UseQueryCache, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); + } + + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + + mapper.Class( + rc => + { + rc.Id(x => x.Id); + rc.Bag( + x => x.Children, + m => + { + m.Access(Accessor.Field); + m.Key(k => k.Column("EntityId")); + m.Cascade(Mapping.ByCode.Cascade.All); + }, + r => r.OneToMany()); + + rc.Cache( + cm => + { + cm.Include(CacheInclude.All); + cm.Usage(CacheUsage.ReadWrite); + }); + }); + + mapper.Class( + rc => + { + rc.Id(x => x.Id); + rc.Cache( + cm => + { + cm.Include(CacheInclude.All); + cm.Usage(CacheUsage.ReadWrite); + }); + }); + + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var entity = new Entity { Id = EntityId.Id1 }; + entity.Children.Add(new ChildEntity { Id = 0 }); + entity.Children.Add(new ChildEntity { Id = 1 }); + session.Save(entity); + + transaction.Commit(); + } + + 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(); + } + + [Test] + public async Task LoadsEntityWithEnumIdAndChildrenUsingQueryCacheAsync() + { + await (LoadEntityWithQueryCacheAsync()); // warm up cache + + var entity = await (LoadEntityWithQueryCacheAsync()); + + Assert.That(entity.Children.Count(), Is.EqualTo(2)); + + Assert.That(Sfi.Statistics.QueryExecutionCount, Is.EqualTo(1), "Unexpected execution count"); + Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(1), "Unexpected cache put count"); + Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(1), "Unexpected cache hit count"); + } + + private async Task LoadEntityWithQueryCacheAsync(CancellationToken cancellationToken = default(CancellationToken)) + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + var entity = (await (session + .Query() + .FetchMany(x => x.Children) + .WithOptions(opt => opt.SetCacheable(true)) + .ToListAsync(cancellationToken)))[0]; + + await (transaction.CommitAsync(cancellationToken)); + return entity; + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3643/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3643/Entity.cs new file mode 100644 index 0000000000..09f08d8dba --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3643/Entity.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; + +// ReSharper disable CollectionNeverUpdated.Local +// ReSharper disable UnassignedGetOnlyAutoProperty + +namespace NHibernate.Test.NHSpecificTest.GH3643 +{ + class Entity + { + private readonly ICollection _children = []; + public virtual EntityId Id { get; set; } + public virtual ICollection Children => _children; + } + + class ChildEntity + { + public virtual int Id { get; set; } + } + + enum EntityId + { + Id1, + Id2 + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3643/FixtureByCode.cs b/src/NHibernate.Test/NHSpecificTest/GH3643/FixtureByCode.cs new file mode 100644 index 0000000000..2fc0741b48 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3643/FixtureByCode.cs @@ -0,0 +1,112 @@ +using System.Linq; +using NHibernate.Cfg; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Linq; +using NHibernate.Mapping.ByCode; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3643 +{ + [TestFixture] + public class FixtureByCode : TestCaseMappingByCode + { + protected override void Configure(Configuration configuration) + { + configuration.SetProperty(Environment.UseQueryCache, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); + } + + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + + mapper.Class( + rc => + { + rc.Id(x => x.Id); + rc.Bag( + x => x.Children, + m => + { + m.Access(Accessor.Field); + m.Key(k => k.Column("EntityId")); + m.Cascade(Mapping.ByCode.Cascade.All); + }, + r => r.OneToMany()); + + rc.Cache( + cm => + { + cm.Include(CacheInclude.All); + cm.Usage(CacheUsage.ReadWrite); + }); + }); + + mapper.Class( + rc => + { + rc.Id(x => x.Id); + rc.Cache( + cm => + { + cm.Include(CacheInclude.All); + cm.Usage(CacheUsage.ReadWrite); + }); + }); + + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var entity = new Entity { Id = EntityId.Id1 }; + entity.Children.Add(new ChildEntity { Id = 0 }); + entity.Children.Add(new ChildEntity { Id = 1 }); + session.Save(entity); + + transaction.Commit(); + } + + 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(); + } + + [Test] + public void LoadsEntityWithEnumIdAndChildrenUsingQueryCache() + { + LoadEntityWithQueryCache(); // warm up cache + + var entity = LoadEntityWithQueryCache(); + + Assert.That(entity.Children.Count(), Is.EqualTo(2)); + + Assert.That(Sfi.Statistics.QueryExecutionCount, Is.EqualTo(1), "Unexpected execution count"); + Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(1), "Unexpected cache put count"); + Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(1), "Unexpected cache hit count"); + } + + private Entity LoadEntityWithQueryCache() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + var entity = session + .Query() + .FetchMany(x => x.Children) + .WithOptions(opt => opt.SetCacheable(true)) + .ToList()[0]; + + transaction.Commit(); + return entity; + } + } +} diff --git a/src/NHibernate/Async/Type/TypeHelper.cs b/src/NHibernate/Async/Type/TypeHelper.cs index 3446d11524..0f04ceebb7 100644 --- a/src/NHibernate/Async/Type/TypeHelper.cs +++ b/src/NHibernate/Async/Type/TypeHelper.cs @@ -125,6 +125,7 @@ internal static async Task InitializeCollectionsAsync( continue; } + value = await (pair.Value.KeyType.AssembleAsync(value, session, null, cancellationToken)).ConfigureAwait(false); var collection = session.PersistenceContext.GetCollection(new CollectionKey(pair.Value, value)); await (collection.ForceInitializationAsync(cancellationToken)).ConfigureAwait(false); assembleRow[pair.Key] = collection; diff --git a/src/NHibernate/Type/TypeHelper.cs b/src/NHibernate/Type/TypeHelper.cs index 1e28e73c8a..d7278d4a38 100644 --- a/src/NHibernate/Type/TypeHelper.cs +++ b/src/NHibernate/Type/TypeHelper.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using NHibernate.Collection; @@ -133,6 +133,7 @@ internal static void InitializeCollections( continue; } + value = pair.Value.KeyType.Assemble(value, session, null); var collection = session.PersistenceContext.GetCollection(new CollectionKey(pair.Value, value)); collection.ForceInitialization(); assembleRow[pair.Key] = collection;