From 6631968bfa2e61b8909b9c93540634fe04e43a37 Mon Sep 17 00:00:00 2001 From: Christoph Watzl Date: Tue, 21 Jan 2025 19:26:24 +0100 Subject: [PATCH 1/2] Provide test case for #3643 --- .../NHSpecificTest/GH3643/Entity.cs | 27 ++++ .../NHSpecificTest/GH3643/FixtureByCode.cs | 118 ++++++++++++++++++ src/NHibernate.sln.DotSettings | 4 + 3 files changed, 149 insertions(+) create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3643/Entity.cs create mode 100644 src/NHibernate.Test/NHSpecificTest/GH3643/FixtureByCode.cs diff --git a/src/NHibernate.Test/NHSpecificTest/GH3643/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3643/Entity.cs new file mode 100644 index 00000000000..60a3de3c863 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3643/Entity.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +// ReSharper disable CollectionNeverUpdated.Local +// ReSharper disable UnassignedGetOnlyAutoProperty + +namespace NHibernate.Test.NHSpecificTest.GH3643 +{ + class Entity + { + private readonly ICollection _children = new List(); + public virtual EntityId Id { get; protected set; } + public virtual IEnumerable Children => _children.AsEnumerable(); + } + + class ChildEntity + { + public virtual int Id { get; protected 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 00000000000..c2694e3b637 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3643/FixtureByCode.cs @@ -0,0 +1,118 @@ +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")); + }, + 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(); + + session.CreateSQLQuery( + "INSERT INTO Entity (Id) VALUES (0)" + ).ExecuteUpdate(); + + session.CreateSQLQuery( + "INSERT INTO ChildEntity (Id, EntityId) VALUES (0, 0)" + ).ExecuteUpdate(); + + session.CreateSQLQuery( + "INSERT INTO ChildEntity (Id, EntityId) VALUES (1, 0)" + ).ExecuteUpdate(); + + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + session.CreateSQLQuery("DELETE FROM ChildEntity").ExecuteUpdate(); + session.CreateSQLQuery("DELETE FROM Entity").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.sln.DotSettings b/src/NHibernate.sln.DotSettings index d78384192e9..b77ef433c2a 100644 --- a/src/NHibernate.sln.DotSettings +++ b/src/NHibernate.sln.DotSettings @@ -21,6 +21,9 @@ <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /> <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy><Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static readonly fields (private)"><ElementKinds><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb" /></Policy> + <Policy><Descriptor Staticness="Any" AccessRightKinds="Private" Description="Constant fields (private)"><ElementKinds><Kind Name="CONSTANT_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="aaBb" /></Policy> + <Policy><Descriptor Staticness="Instance" AccessRightKinds="Private" Description="Instance fields (private)"><ElementKinds><Kind Name="FIELD" /><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="_" Suffix="" Style="aaBb" /></Policy> True True True @@ -29,6 +32,7 @@ True True True + True True True True From 3b29f38ab01a8980336d5638c3010d91739317a2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 28 Jan 2025 14:43:57 +0000 Subject: [PATCH 2/2] Generate async files --- .../NHSpecificTest/GH3643/FixtureByCode.cs | 130 ++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 src/NHibernate.Test/Async/NHSpecificTest/GH3643/FixtureByCode.cs 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 00000000000..7f40824898d --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3643/FixtureByCode.cs @@ -0,0 +1,130 @@ +//------------------------------------------------------------------------------ +// +// 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")); + }, + 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(); + + session.CreateSQLQuery( + "INSERT INTO Entity (Id) VALUES (0)" + ).ExecuteUpdate(); + + session.CreateSQLQuery( + "INSERT INTO ChildEntity (Id, EntityId) VALUES (0, 0)" + ).ExecuteUpdate(); + + session.CreateSQLQuery( + "INSERT INTO ChildEntity (Id, EntityId) VALUES (1, 0)" + ).ExecuteUpdate(); + + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + session.CreateSQLQuery("DELETE FROM ChildEntity").ExecuteUpdate(); + session.CreateSQLQuery("DELETE FROM Entity").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; + } + } +}