Skip to content

Commit d32a9d9

Browse files
Merge 5.4.4 into master
2 parents c4c711d + dd17017 commit d32a9d9

23 files changed

+573
-30
lines changed

releasenotes.txt

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,27 @@
1-
Build 5.4.3
1+
Build 5.4.4
2+
=============================
3+
4+
Release notes - NHibernate - Version 5.4.4
5+
6+
6 issues were resolved in this release.
7+
8+
** Bug
9+
10+
* #3359 2nd level cache GetMany ineffective for collections
11+
* #3354 Invalid program generated by FieldInterceptorProxyBuilder for indexer property getter
12+
* #3352 Fetch throws "could not resolve property" error for a property that is not mapped
13+
14+
** Improvement
15+
16+
* #3368 Allow internal entity classes/interfaces in .NET Standard 2.0 for field interceptor
17+
18+
** Task
19+
20+
* #3386 Release 5.4.4
21+
* #3367 Update readme with actual dev build information for 5.4
22+
23+
24+
Build 5.4.3
225
=============================
326

427
Release notes - NHibernate - Version 5.4.3

src/NHibernate.Test/Async/CacheTest/BatchableCacheFixture.cs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1565,8 +1565,31 @@ public async Task QueryFetchEntityBatchCacheTestAsync(bool clearEntityCacheAfter
15651565
Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(future ? 2 : 1), "Unexpected cache hit count");
15661566
}
15671567

1568+
[Test]
1569+
public async Task CollectionLazyInitializationFromCacheIsBatchedAsync()
1570+
{
1571+
using (var s = OpenSession())
1572+
{
1573+
var readOnly = await (s.GetAsync<ReadOnly>(await (s.Query<ReadOnly>().Select(x => x.Id).FirstAsync())));
1574+
Assert.That(readOnly.Items.Count, Is.EqualTo(6));
1575+
}
1576+
1577+
var itemPersister = Sfi.GetEntityPersister(typeof(ReadOnlyItem).FullName);
1578+
var itemCache = (BatchableCache) itemPersister.Cache.Cache;
1579+
itemCache.ClearStatistics();
1580+
1581+
using (var s = OpenSession())
1582+
{
1583+
var readOnly = await (s.GetAsync<ReadOnly>(await (s.Query<ReadOnly>().Select(x => x.Id).FirstAsync())));
1584+
Assert.That(readOnly.Items.Count, Is.EqualTo(6));
1585+
}
1586+
1587+
// 6 items with batch-size = 4 so 2 GetMany calls are expected 1st call: 4 items + 2nd call: 2 items
1588+
Assert.That(itemCache.GetMultipleCalls.Count, Is.EqualTo(2));
1589+
}
1590+
15681591
private async Task AssertMultipleCacheCallsAsync<TEntity>(IEnumerable<int> loadIds, IReadOnlyList<int> getIds, int idIndex,
1569-
int[][] fetchedIdIndexes, int[] putIdIndexes, Func<int, bool> cacheBeforeLoadFn = null, CancellationToken cancellationToken = default(CancellationToken))
1592+
int[][] fetchedIdIndexes, int[] putIdIndexes, Func<int, bool> cacheBeforeLoadFn = null, CancellationToken cancellationToken = default(CancellationToken))
15701593
where TEntity : CacheEntity
15711594
{
15721595
var persister = Sfi.GetEntityPersister(typeof(TEntity).FullName);

src/NHibernate.Test/Async/LazyProperty/LazyPropertyFixture.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,9 @@ public async Task CanGetValueForNonLazyPropertyAsync()
230230
Assert.That(book.Name, Is.EqualTo("some name"));
231231
Assert.That(book.FieldInterceptor, Is.EqualTo("Why not that name?"));
232232
Assert.That(NHibernateUtil.IsPropertyInitialized(book, "ALotOfText"), Is.False);
233+
//GH-3354 Exception accessing indexer property
234+
Assert.That(book[0], Is.EqualTo(0));
235+
Assert.DoesNotThrow(() => book[0] = 0);
233236
}
234237
}
235238

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
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.MappingSchema;
13+
using NHibernate.Linq;
14+
using NHibernate.Mapping.ByCode;
15+
using NUnit.Framework;
16+
17+
namespace NHibernate.Test.NHSpecificTest.GH3352
18+
{
19+
using System.Threading.Tasks;
20+
[TestFixture]
21+
public class FetchFromNotMappedBaseClassFixtureAsync : TestCaseMappingByCode
22+
{
23+
protected override HbmMapping GetMappings()
24+
{
25+
var mapper = new ModelMapper();
26+
mapper.Class<EntityNameMapped>(rc =>
27+
{
28+
rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb));
29+
rc.Property(x => x.Name, m => m.Lazy(true));
30+
});
31+
mapper.Class<EntityParentMapped>(rc =>
32+
{
33+
rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb));
34+
rc.ManyToOne(x => x.Parent, m => m.ForeignKey("none"));
35+
});
36+
mapper.Class<EntityComponentMapped>(rc =>
37+
{
38+
rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb));
39+
rc.Component(x => x.Component);
40+
});
41+
mapper.Component<Component>(rc =>
42+
{
43+
rc.Property(x => x.Field);
44+
rc.ManyToOne(x => x.Entity, m => m.ForeignKey("none"));
45+
rc.Lazy(true);
46+
});
47+
return mapper.CompileMappingForAllExplicitlyAddedEntities();
48+
}
49+
50+
protected override void OnSetUp()
51+
{
52+
using var session = OpenSession();
53+
using var transaction = session.BeginTransaction();
54+
var np = new EntityComponentMapped { Component = new Component { Field = "x" } };
55+
session.Save(np);
56+
var e = new EntityParentMapped { Parent = np };
57+
session.Save(e);
58+
var nameMapped = new EntityNameMapped { Name = "lazy" };
59+
session.Save(nameMapped);
60+
np.Component.Entity = nameMapped;
61+
62+
transaction.Commit();
63+
}
64+
65+
protected override void OnTearDown()
66+
{
67+
using var session = OpenSession();
68+
using var transaction = session.BeginTransaction();
69+
session.CreateQuery("delete from System.Object").ExecuteUpdate();
70+
71+
transaction.Commit();
72+
}
73+
74+
[Test]
75+
public async Task CanFetchLazyComponentFromNotMappedBaseClassAsync()
76+
{
77+
using var session = OpenSession();
78+
var list = await (session.Query<EntityComponentMapped>().Fetch(x => x.Component).ToListAsync());
79+
80+
Assert.That(list, Has.Count.EqualTo(1));
81+
var result = list[0];
82+
Assert.That(NHibernateUtil.IsPropertyInitialized(result, nameof(result.Component)));
83+
Assert.That(result.Component.Field, Is.EqualTo("x"));
84+
}
85+
86+
[Test]
87+
public async Task CanFetchLazyComponentThenEntityFromNotMappedBaseClassAsync()
88+
{
89+
using var session = OpenSession();
90+
var list = await (session.Query<EntityComponentMapped>()
91+
.Fetch(x => x.Component)
92+
.ThenFetch(x => x.Entity)
93+
.ThenFetch(x => x.Name)
94+
.ToListAsync());
95+
96+
Assert.That(list, Has.Count.EqualTo(1));
97+
var result = list[0];
98+
Assert.That(NHibernateUtil.IsPropertyInitialized(result, nameof(result.Component)));
99+
Assert.That(result.Component.Field, Is.EqualTo("x"));
100+
Assert.That(result.Component.Entity, Is.Not.Null);
101+
Assert.That(NHibernateUtil.IsInitialized(result.Component.Entity), Is.True);
102+
Assert.That(NHibernateUtil.IsPropertyInitialized(result.Component.Entity, nameof(result.Name)), Is.True);
103+
Assert.That(result.Component.Entity.Name, Is.EqualTo("lazy"));
104+
}
105+
106+
[Test]
107+
public async Task CanFetchLazyPropertyFromNotMappedBaseClassAsync()
108+
{
109+
using var session = OpenSession();
110+
var list = await (session.Query<EntityNameMapped>().Fetch(x => x.Name).ToListAsync());
111+
112+
Assert.That(list, Has.Count.EqualTo(1));
113+
var result = list[0];
114+
Assert.That(NHibernateUtil.IsPropertyInitialized(result, nameof(result.Name)));
115+
Assert.That(result.Name, Is.EqualTo("lazy"));
116+
}
117+
118+
[Test]
119+
public async Task CanThenFetchLazyComponentFromNotMappedBaseClassAsync()
120+
{
121+
using var session = OpenSession();
122+
var list = await (session.Query<EntityParentMapped>().Fetch(x => x.Parent).ThenFetch(x => x.Component).ToListAsync());
123+
124+
Assert.That(list, Has.Count.EqualTo(1));
125+
var result = list[0].Parent;
126+
Assert.That(NHibernateUtil.IsInitialized(result), Is.True);
127+
Assert.That(NHibernateUtil.IsPropertyInitialized(result, nameof(result.Component)));
128+
Assert.That(result.Component.Field, Is.EqualTo("x"));
129+
}
130+
131+
[KnownBug("GH-3356")]
132+
[Test(Description = "GH-3356" )]
133+
public async Task FetchAfterSelectAsync()
134+
{
135+
using var log = new SqlLogSpy();
136+
137+
using var s = OpenSession();
138+
var list = await (s.Query<EntityParentMapped>()
139+
.Select(x => x.Parent)
140+
.Fetch(x => x.Component)
141+
.ThenFetch(x => x.Entity)
142+
.ThenFetch(x => x.Name)
143+
.ToListAsync());
144+
Assert.That(list, Has.Count.EqualTo(1));
145+
var result = list[0];
146+
Assert.That(NHibernateUtil.IsPropertyInitialized(result, nameof(result.Component)));
147+
Assert.That(result.Component.Field, Is.EqualTo("x"));
148+
Assert.That(result.Component.Entity, Is.Not.Null);
149+
Assert.That(NHibernateUtil.IsInitialized(result.Component.Entity), Is.True);
150+
Assert.That(NHibernateUtil.IsPropertyInitialized(result.Component.Entity, nameof(result.Name)), Is.True);
151+
Assert.That(result.Component.Entity.Name, Is.EqualTo("lazy"));
152+
}
153+
154+
[Test]
155+
public async Task CanFetchEntityFromNotMappedBaseClassAsync()
156+
{
157+
using var session = OpenSession();
158+
var list = await (session.Query<EntityParentMapped>().Fetch(x => x.Parent).ToListAsync());
159+
160+
Assert.That(list, Has.Count.EqualTo(1));
161+
Assert.That(list[0].Parent, Is.Not.Null);
162+
Assert.That(NHibernateUtil.IsInitialized(list[0].Parent));
163+
}
164+
165+
[Test]
166+
public void FetchNotMappedAssociationThrowsAsync()
167+
{
168+
using var session = OpenSession();
169+
var query = session.Query<EntityNameMapped>().Fetch(x => x.Parent);
170+
171+
Assert.ThrowsAsync<QueryException>(() => query.ToListAsync());
172+
}
173+
}
174+
}

src/NHibernate.Test/CacheTest/BatchableCacheFixture.cs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1553,8 +1553,31 @@ public void QueryFetchEntityBatchCacheTest(bool clearEntityCacheAfterQuery, bool
15531553
Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(future ? 2 : 1), "Unexpected cache hit count");
15541554
}
15551555

1556+
[Test]
1557+
public void CollectionLazyInitializationFromCacheIsBatched()
1558+
{
1559+
using (var s = OpenSession())
1560+
{
1561+
var readOnly = s.Get<ReadOnly>(s.Query<ReadOnly>().Select(x => x.Id).First());
1562+
Assert.That(readOnly.Items.Count, Is.EqualTo(6));
1563+
}
1564+
1565+
var itemPersister = Sfi.GetEntityPersister(typeof(ReadOnlyItem).FullName);
1566+
var itemCache = (BatchableCache) itemPersister.Cache.Cache;
1567+
itemCache.ClearStatistics();
1568+
1569+
using (var s = OpenSession())
1570+
{
1571+
var readOnly = s.Get<ReadOnly>(s.Query<ReadOnly>().Select(x => x.Id).First());
1572+
Assert.That(readOnly.Items.Count, Is.EqualTo(6));
1573+
}
1574+
1575+
// 6 items with batch-size = 4 so 2 GetMany calls are expected 1st call: 4 items + 2nd call: 2 items
1576+
Assert.That(itemCache.GetMultipleCalls.Count, Is.EqualTo(2));
1577+
}
1578+
15561579
private void AssertMultipleCacheCalls<TEntity>(IEnumerable<int> loadIds, IReadOnlyList<int> getIds, int idIndex,
1557-
int[][] fetchedIdIndexes, int[] putIdIndexes, Func<int, bool> cacheBeforeLoadFn = null)
1580+
int[][] fetchedIdIndexes, int[] putIdIndexes, Func<int, bool> cacheBeforeLoadFn = null)
15581581
where TEntity : CacheEntity
15591582
{
15601583
var persister = Sfi.GetEntityPersister(typeof(TEntity).FullName);

src/NHibernate.Test/LazyProperty/Book.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,11 @@ public virtual byte[] NoSetterImage
2828
public virtual string FieldInterceptor { get; set; }
2929

3030
public virtual IList<Word> Words { get; set; }
31+
32+
public virtual int this[int i]
33+
{
34+
get { return i;}
35+
set { }
36+
}
3137
}
3238
}

src/NHibernate.Test/LazyProperty/LazyPropertyFixture.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,9 @@ public void CanGetValueForNonLazyProperty()
225225
Assert.That(book.Name, Is.EqualTo("some name"));
226226
Assert.That(book.FieldInterceptor, Is.EqualTo("Why not that name?"));
227227
Assert.That(NHibernateUtil.IsPropertyInitialized(book, "ALotOfText"), Is.False);
228+
//GH-3354 Exception accessing indexer property
229+
Assert.That(book[0], Is.EqualTo(0));
230+
Assert.DoesNotThrow(() => book[0] = 0);
228231
}
229232
}
230233

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
3+
namespace NHibernate.Test.NHSpecificTest.GH3352
4+
{
5+
public class Entity
6+
{
7+
public virtual Guid Id { get; set; }
8+
public virtual string Name { get; set; }
9+
public virtual EntityComponentMapped Parent { get; set; }
10+
public virtual Component Component { get; set; }
11+
}
12+
13+
public class EntityNameMapped : Entity
14+
{
15+
}
16+
17+
public class EntityParentMapped : Entity
18+
{
19+
}
20+
21+
public class EntityComponentMapped : Entity
22+
{
23+
}
24+
25+
public class Component
26+
{
27+
public string Field { get; set; }
28+
29+
public EntityNameMapped Entity { get; set; }
30+
}
31+
}

0 commit comments

Comments
 (0)