Skip to content

Commit 3bfbdb7

Browse files
fredericDelaportecwatzl
authored andcommitted
Fix collection cache lookup failure with enum keys (#3693)
Co-authored-by: Christoph Watzl <[email protected]> (cherry picked from commit 66300c1)
1 parent e9b5d23 commit 3bfbdb7

File tree

5 files changed

+264
-1
lines changed

5 files changed

+264
-1
lines changed
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
//------------------------------------------------------------------------------
2+
// <auto-generated>
3+
// This code was generated by AsyncGenerator.
4+
//
5+
// Changes to this file may cause incorrect behavior and will be lost if
6+
// the code is regenerated.
7+
// </auto-generated>
8+
//------------------------------------------------------------------------------
9+
10+
11+
using System.Linq;
12+
using NHibernate.Cfg;
13+
using NHibernate.Cfg.MappingSchema;
14+
using NHibernate.Linq;
15+
using NHibernate.Mapping.ByCode;
16+
using NUnit.Framework;
17+
18+
namespace NHibernate.Test.NHSpecificTest.GH3643
19+
{
20+
using System.Threading.Tasks;
21+
using System.Threading;
22+
[TestFixture]
23+
public class FixtureByCodeAsync : TestCaseMappingByCode
24+
{
25+
protected override void Configure(Configuration configuration)
26+
{
27+
configuration.SetProperty(Environment.UseQueryCache, "true");
28+
configuration.SetProperty(Environment.GenerateStatistics, "true");
29+
}
30+
31+
protected override HbmMapping GetMappings()
32+
{
33+
var mapper = new ModelMapper();
34+
35+
mapper.Class<Entity>(
36+
rc =>
37+
{
38+
rc.Id(x => x.Id);
39+
rc.Bag(
40+
x => x.Children,
41+
m =>
42+
{
43+
m.Access(Accessor.Field);
44+
m.Key(k => k.Column("EntityId"));
45+
m.Cascade(Mapping.ByCode.Cascade.All);
46+
},
47+
r => r.OneToMany());
48+
49+
rc.Cache(
50+
cm =>
51+
{
52+
cm.Include(CacheInclude.All);
53+
cm.Usage(CacheUsage.ReadWrite);
54+
});
55+
});
56+
57+
mapper.Class<ChildEntity>(
58+
rc =>
59+
{
60+
rc.Id(x => x.Id);
61+
rc.Cache(
62+
cm =>
63+
{
64+
cm.Include(CacheInclude.All);
65+
cm.Usage(CacheUsage.ReadWrite);
66+
});
67+
});
68+
69+
return mapper.CompileMappingForAllExplicitlyAddedEntities();
70+
}
71+
72+
protected override void OnSetUp()
73+
{
74+
using var session = OpenSession();
75+
using var transaction = session.BeginTransaction();
76+
77+
var entity = new Entity { Id = EntityId.Id1 };
78+
entity.Children.Add(new ChildEntity { Id = 0 });
79+
entity.Children.Add(new ChildEntity { Id = 1 });
80+
session.Save(entity);
81+
82+
transaction.Commit();
83+
}
84+
85+
protected override void OnTearDown()
86+
{
87+
using var session = OpenSession();
88+
using var transaction = session.BeginTransaction();
89+
90+
session.CreateQuery("delete from ChildEntity").ExecuteUpdate();
91+
session.CreateQuery("delete from System.Object").ExecuteUpdate();
92+
93+
transaction.Commit();
94+
}
95+
96+
[Test]
97+
public async Task LoadsEntityWithEnumIdAndChildrenUsingQueryCacheAsync()
98+
{
99+
await (LoadEntityWithQueryCacheAsync()); // warm up cache
100+
101+
var entity = await (LoadEntityWithQueryCacheAsync());
102+
103+
Assert.That(entity.Children.Count(), Is.EqualTo(2));
104+
105+
Assert.That(Sfi.Statistics.QueryExecutionCount, Is.EqualTo(1), "Unexpected execution count");
106+
Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(1), "Unexpected cache put count");
107+
Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(1), "Unexpected cache hit count");
108+
}
109+
110+
private async Task<Entity> LoadEntityWithQueryCacheAsync(CancellationToken cancellationToken = default(CancellationToken))
111+
{
112+
using var session = OpenSession();
113+
using var transaction = session.BeginTransaction();
114+
var entity = (await (session
115+
.Query<Entity>()
116+
.FetchMany(x => x.Children)
117+
.WithOptions(opt => opt.SetCacheable(true))
118+
.ToListAsync(cancellationToken)))[0];
119+
120+
await (transaction.CommitAsync(cancellationToken));
121+
return entity;
122+
}
123+
}
124+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System.Collections.Generic;
2+
3+
// ReSharper disable CollectionNeverUpdated.Local
4+
// ReSharper disable UnassignedGetOnlyAutoProperty
5+
6+
namespace NHibernate.Test.NHSpecificTest.GH3643
7+
{
8+
class Entity
9+
{
10+
private readonly ICollection<ChildEntity> _children = [];
11+
public virtual EntityId Id { get; set; }
12+
public virtual ICollection<ChildEntity> Children => _children;
13+
}
14+
15+
class ChildEntity
16+
{
17+
public virtual int Id { get; set; }
18+
}
19+
20+
enum EntityId
21+
{
22+
Id1,
23+
Id2
24+
}
25+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
using System.Linq;
2+
using NHibernate.Cfg;
3+
using NHibernate.Cfg.MappingSchema;
4+
using NHibernate.Linq;
5+
using NHibernate.Mapping.ByCode;
6+
using NUnit.Framework;
7+
8+
namespace NHibernate.Test.NHSpecificTest.GH3643
9+
{
10+
[TestFixture]
11+
public class FixtureByCode : TestCaseMappingByCode
12+
{
13+
protected override void Configure(Configuration configuration)
14+
{
15+
configuration.SetProperty(Environment.UseQueryCache, "true");
16+
configuration.SetProperty(Environment.GenerateStatistics, "true");
17+
}
18+
19+
protected override HbmMapping GetMappings()
20+
{
21+
var mapper = new ModelMapper();
22+
23+
mapper.Class<Entity>(
24+
rc =>
25+
{
26+
rc.Id(x => x.Id);
27+
rc.Bag(
28+
x => x.Children,
29+
m =>
30+
{
31+
m.Access(Accessor.Field);
32+
m.Key(k => k.Column("EntityId"));
33+
m.Cascade(Mapping.ByCode.Cascade.All);
34+
},
35+
r => r.OneToMany());
36+
37+
rc.Cache(
38+
cm =>
39+
{
40+
cm.Include(CacheInclude.All);
41+
cm.Usage(CacheUsage.ReadWrite);
42+
});
43+
});
44+
45+
mapper.Class<ChildEntity>(
46+
rc =>
47+
{
48+
rc.Id(x => x.Id);
49+
rc.Cache(
50+
cm =>
51+
{
52+
cm.Include(CacheInclude.All);
53+
cm.Usage(CacheUsage.ReadWrite);
54+
});
55+
});
56+
57+
return mapper.CompileMappingForAllExplicitlyAddedEntities();
58+
}
59+
60+
protected override void OnSetUp()
61+
{
62+
using var session = OpenSession();
63+
using var transaction = session.BeginTransaction();
64+
65+
var entity = new Entity { Id = EntityId.Id1 };
66+
entity.Children.Add(new ChildEntity { Id = 0 });
67+
entity.Children.Add(new ChildEntity { Id = 1 });
68+
session.Save(entity);
69+
70+
transaction.Commit();
71+
}
72+
73+
protected override void OnTearDown()
74+
{
75+
using var session = OpenSession();
76+
using var transaction = session.BeginTransaction();
77+
78+
session.CreateQuery("delete from ChildEntity").ExecuteUpdate();
79+
session.CreateQuery("delete from System.Object").ExecuteUpdate();
80+
81+
transaction.Commit();
82+
}
83+
84+
[Test]
85+
public void LoadsEntityWithEnumIdAndChildrenUsingQueryCache()
86+
{
87+
LoadEntityWithQueryCache(); // warm up cache
88+
89+
var entity = LoadEntityWithQueryCache();
90+
91+
Assert.That(entity.Children.Count(), Is.EqualTo(2));
92+
93+
Assert.That(Sfi.Statistics.QueryExecutionCount, Is.EqualTo(1), "Unexpected execution count");
94+
Assert.That(Sfi.Statistics.QueryCachePutCount, Is.EqualTo(1), "Unexpected cache put count");
95+
Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(1), "Unexpected cache hit count");
96+
}
97+
98+
private Entity LoadEntityWithQueryCache()
99+
{
100+
using var session = OpenSession();
101+
using var transaction = session.BeginTransaction();
102+
var entity = session
103+
.Query<Entity>()
104+
.FetchMany(x => x.Children)
105+
.WithOptions(opt => opt.SetCacheable(true))
106+
.ToList()[0];
107+
108+
transaction.Commit();
109+
return entity;
110+
}
111+
}
112+
}

src/NHibernate/Async/Type/TypeHelper.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ internal static async Task InitializeCollectionsAsync(
125125
continue;
126126
}
127127

128+
value = await (pair.Value.KeyType.AssembleAsync(value, session, null, cancellationToken)).ConfigureAwait(false);
128129
var collection = session.PersistenceContext.GetCollection(new CollectionKey(pair.Value, value));
129130
await (collection.ForceInitializationAsync(cancellationToken)).ConfigureAwait(false);
130131
assembleRow[pair.Key] = collection;

src/NHibernate/Type/TypeHelper.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using System;
1+
using System;
22
using System.Collections;
33
using System.Collections.Generic;
44
using NHibernate.Collection;
@@ -133,6 +133,7 @@ internal static void InitializeCollections(
133133
continue;
134134
}
135135

136+
value = pair.Value.KeyType.Assemble(value, session, null);
136137
var collection = session.PersistenceContext.GetCollection(new CollectionKey(pair.Value, value));
137138
collection.ForceInitialization();
138139
assembleRow[pair.Key] = collection;

0 commit comments

Comments
 (0)