Skip to content

Commit 412e529

Browse files
Merge 5.3.18 into 5.4.x
2 parents e2e6cbe + 218379c commit 412e529

File tree

10 files changed

+241
-7
lines changed

10 files changed

+241
-7
lines changed

releasenotes.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,23 @@ Release notes - NHibernate - Version 5.4.0
234234
* #2242 Test case for NH-3972 - SQL error when selecting a column of a subclass when sibling classes have a column of the same name
235235

236236

237+
Build 5.3.18
238+
=============================
239+
240+
Release notes - NHibernate - Version 5.3.18
241+
242+
3 issues were resolved in this release.
243+
244+
** Bug
245+
246+
* #3333 Lazy property with nosetter accessor remains uninitialized
247+
* #3330 Linq with FetchLazyProperties() resets lazy property changes
248+
249+
** Task
250+
251+
* #3346 Release 5.3.18
252+
253+
237254
Build 5.3.17
238255
=============================
239256

src/NHibernate.Test/Async/FetchLazyProperties/FetchLazyPropertiesFixture.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,45 @@ public async Task TestLinqFetchAllPropertiesAsync()
276276
AssertFetchAllProperties(person);
277277
}
278278

279+
[TestCase(true)]
280+
[TestCase(false)]
281+
public async Task TestLinqFetchAllProperties_WhenLazyPropertyChangedAsync(bool initLazyPropertyFetchGroup)
282+
{
283+
Person person;
284+
using (var s = OpenSession())
285+
{
286+
person = await (s.GetAsync<Person>(1));
287+
if (initLazyPropertyFetchGroup)
288+
CollectionAssert.AreEqual(new byte[] { 0 }, person.Image);
289+
290+
person.Image = new byte[] { 1, 2, 3 };
291+
292+
var allPersons = await (s.Query<Person>().FetchLazyProperties().ToListAsync());
293+
// After execute FetchLazyProperties(), I expected to see that the person.Image would be { 1, 2, 3 }.
294+
// Because I changed this person.Image manually, I didn't want to lose those changes.
295+
// But test failed. Оld value returned { 0 }.
296+
CollectionAssert.AreEqual(new byte[] { 1, 2, 3 }, person.Image);
297+
}
298+
}
299+
300+
[TestCase(true)]
301+
[TestCase(false)]
302+
public async Task TestLinqFetchProperty_WhenLazyPropertyChangedAsync(bool initLazyPropertyFetchGroup)
303+
{
304+
Person person;
305+
using (var s = OpenSession())
306+
{
307+
person = await (s.GetAsync<Person>(1));
308+
if (initLazyPropertyFetchGroup)
309+
CollectionAssert.AreEqual(new byte[] { 0 }, person.Image);
310+
311+
person.Image = new byte[] { 1, 2, 3 };
312+
313+
var allPersons = await (s.Query<Person>().Fetch(x => x.Image).ToListAsync());
314+
CollectionAssert.AreEqual(new byte[] { 1, 2, 3 }, person.Image);
315+
}
316+
}
317+
279318
private static void AssertFetchAllProperties(Person person)
280319
{
281320
Assert.That(person, Is.Not.Null);

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

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
using System.Linq;
1414
using NHibernate.Cfg;
1515
using NHibernate.Intercept;
16+
using NHibernate.Linq;
1617
using NHibernate.Tuple.Entity;
1718
using NUnit.Framework;
1819
using NUnit.Framework.Constraints;
19-
using NHibernate.Linq;
2020

2121
namespace NHibernate.Test.LazyProperty
2222
{
@@ -67,6 +67,7 @@ protected override void OnSetUp()
6767
Id = 1,
6868
ALotOfText = "a lot of text ...",
6969
Image = new byte[10],
70+
NoSetterImage = new byte[10],
7071
FieldInterceptor = "Why not that name?"
7172
});
7273
tx.Commit();
@@ -391,5 +392,58 @@ public async Task CanMergeTransientWithLazyPropertyInCollectionAsync()
391392
Assert.That(book.Words.First().Content, Is.EqualTo(new byte[1] { 0 }));
392393
}
393394
}
395+
396+
[Test(Description = "GH-3333")]
397+
public async Task GetLazyPropertyWithNoSetterAccessor_PropertyShouldBeInitializedAsync()
398+
{
399+
using (ISession s = OpenSession())
400+
{
401+
var book = await (s.GetAsync<Book>(1));
402+
var image = book.NoSetterImage;
403+
// Fails. Property remains uninitialized after it has been accessed.
404+
Assert.That(NHibernateUtil.IsPropertyInitialized(book, "NoSetterImage"), Is.True);
405+
}
406+
}
407+
408+
[Test(Description = "GH-3333")]
409+
public async Task GetLazyPropertyWithNoSetterAccessorTwice_ResultsAreSameObjectAsync()
410+
{
411+
using (ISession s = OpenSession())
412+
{
413+
var book = await (s.GetAsync<Book>(1));
414+
var image = book.NoSetterImage;
415+
var sameImage = book.NoSetterImage;
416+
// Fails. Each call to a property getter returns a new object.
417+
Assert.That(ReferenceEquals(image, sameImage), Is.True);
418+
}
419+
}
420+
421+
[Test]
422+
public async Task CanSetValueForLazyPropertyNoSetterAsync()
423+
{
424+
Book book;
425+
using (ISession s = OpenSession())
426+
{
427+
book = await (s.GetAsync<Book>(1));
428+
book.NoSetterImage = new byte[]{10};
429+
}
430+
431+
Assert.That(NHibernateUtil.IsPropertyInitialized(book, nameof(book.NoSetterImage)), Is.True);
432+
CollectionAssert.AreEqual(book.NoSetterImage, new byte[] { 10 });
433+
}
434+
435+
[Test]
436+
public async Task CanFetchLazyPropertyNoSetterAsync()
437+
{
438+
using (ISession s = OpenSession())
439+
{
440+
var book = await (s
441+
.Query<Book>()
442+
.Fetch(x => x.NoSetterImage)
443+
.FirstAsync(x => x.Id == 1));
444+
445+
Assert.That(NHibernateUtil.IsPropertyInitialized(book, nameof(book.NoSetterImage)), Is.True);
446+
}
447+
}
394448
}
395449
}

src/NHibernate.Test/FetchLazyProperties/FetchLazyPropertiesFixture.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,45 @@ public void TestLinqFetchAllProperties()
265265
AssertFetchAllProperties(person);
266266
}
267267

268+
[TestCase(true)]
269+
[TestCase(false)]
270+
public void TestLinqFetchAllProperties_WhenLazyPropertyChanged(bool initLazyPropertyFetchGroup)
271+
{
272+
Person person;
273+
using (var s = OpenSession())
274+
{
275+
person = s.Get<Person>(1);
276+
if (initLazyPropertyFetchGroup)
277+
CollectionAssert.AreEqual(new byte[] { 0 }, person.Image);
278+
279+
person.Image = new byte[] { 1, 2, 3 };
280+
281+
var allPersons = s.Query<Person>().FetchLazyProperties().ToList();
282+
// After execute FetchLazyProperties(), I expected to see that the person.Image would be { 1, 2, 3 }.
283+
// Because I changed this person.Image manually, I didn't want to lose those changes.
284+
// But test failed. Оld value returned { 0 }.
285+
CollectionAssert.AreEqual(new byte[] { 1, 2, 3 }, person.Image);
286+
}
287+
}
288+
289+
[TestCase(true)]
290+
[TestCase(false)]
291+
public void TestLinqFetchProperty_WhenLazyPropertyChanged(bool initLazyPropertyFetchGroup)
292+
{
293+
Person person;
294+
using (var s = OpenSession())
295+
{
296+
person = s.Get<Person>(1);
297+
if (initLazyPropertyFetchGroup)
298+
CollectionAssert.AreEqual(new byte[] { 0 }, person.Image);
299+
300+
person.Image = new byte[] { 1, 2, 3 };
301+
302+
var allPersons = s.Query<Person>().Fetch(x => x.Image).ToList();
303+
CollectionAssert.AreEqual(new byte[] { 1, 2, 3 }, person.Image);
304+
}
305+
}
306+
268307
private static void AssertFetchAllProperties(Person person)
269308
{
270309
Assert.That(person, Is.Not.Null);

src/NHibernate.Test/LazyProperty/Book.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ public virtual string ALotOfText
1717

1818
public virtual byte[] Image { get; set; }
1919

20+
private byte[] _NoSetterImage;
21+
22+
public virtual byte[] NoSetterImage
23+
{
24+
get { return _NoSetterImage; }
25+
set { _NoSetterImage = value; }
26+
}
27+
2028
public virtual string FieldInterceptor { get; set; }
2129

2230
public virtual IList<Word> Words { get; set; }

src/NHibernate.Test/LazyProperty/LazyPropertyFixture.cs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Linq;
44
using NHibernate.Cfg;
55
using NHibernate.Intercept;
6+
using NHibernate.Linq;
67
using NHibernate.Tuple.Entity;
78
using NUnit.Framework;
89
using NUnit.Framework.Constraints;
@@ -55,6 +56,7 @@ protected override void OnSetUp()
5556
Id = 1,
5657
ALotOfText = "a lot of text ...",
5758
Image = new byte[10],
59+
NoSetterImage = new byte[10],
5860
FieldInterceptor = "Why not that name?"
5961
});
6062
tx.Commit();
@@ -385,5 +387,58 @@ public void CanMergeTransientWithLazyPropertyInCollection()
385387
Assert.That(book.Words.First().Content, Is.EqualTo(new byte[1] { 0 }));
386388
}
387389
}
390+
391+
[Test(Description = "GH-3333")]
392+
public void GetLazyPropertyWithNoSetterAccessor_PropertyShouldBeInitialized()
393+
{
394+
using (ISession s = OpenSession())
395+
{
396+
var book = s.Get<Book>(1);
397+
var image = book.NoSetterImage;
398+
// Fails. Property remains uninitialized after it has been accessed.
399+
Assert.That(NHibernateUtil.IsPropertyInitialized(book, "NoSetterImage"), Is.True);
400+
}
401+
}
402+
403+
[Test(Description = "GH-3333")]
404+
public void GetLazyPropertyWithNoSetterAccessorTwice_ResultsAreSameObject()
405+
{
406+
using (ISession s = OpenSession())
407+
{
408+
var book = s.Get<Book>(1);
409+
var image = book.NoSetterImage;
410+
var sameImage = book.NoSetterImage;
411+
// Fails. Each call to a property getter returns a new object.
412+
Assert.That(ReferenceEquals(image, sameImage), Is.True);
413+
}
414+
}
415+
416+
[Test]
417+
public void CanSetValueForLazyPropertyNoSetter()
418+
{
419+
Book book;
420+
using (ISession s = OpenSession())
421+
{
422+
book = s.Get<Book>(1);
423+
book.NoSetterImage = new byte[]{10};
424+
}
425+
426+
Assert.That(NHibernateUtil.IsPropertyInitialized(book, nameof(book.NoSetterImage)), Is.True);
427+
CollectionAssert.AreEqual(book.NoSetterImage, new byte[] { 10 });
428+
}
429+
430+
[Test]
431+
public void CanFetchLazyPropertyNoSetter()
432+
{
433+
using (ISession s = OpenSession())
434+
{
435+
var book = s
436+
.Query<Book>()
437+
.Fetch(x => x.NoSetterImage)
438+
.First(x => x.Id == 1);
439+
440+
Assert.That(NHibernateUtil.IsPropertyInitialized(book, nameof(book.NoSetterImage)), Is.True);
441+
}
442+
}
388443
}
389444
}

src/NHibernate.Test/LazyProperty/Mappings.hbm.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
<property name="Name" />
1212
<property name="ALotOfText" lazy="true" />
1313
<property name="Image" lazy="true" />
14+
<property name="NoSetterImage" access="nosetter.pascalcase-underscore" lazy="true" />
1415
<property name="FieldInterceptor" />
1516
<bag name="Words" inverse="true" generic="true" cascade="all-delete-orphan" lazy="true" >
1617
<key column="ParentId" />

src/NHibernate/Async/Loader/Loader.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -798,8 +798,13 @@ private async Task UpdateLazyPropertiesFromResultSetAsync(DbDataReader rs, int i
798798
? persister.EntityMetamodel.BytecodeEnhancementMetadata.GetUninitializedLazyProperties(entry.LoadedState)
799799
: persister.EntityMetamodel.BytecodeEnhancementMetadata.GetUninitializedLazyProperties(obj);
800800

801-
var updateLazyProperties = fetchLazyProperties?.Intersect(uninitializedProperties).ToArray();
802-
if (updateLazyProperties?.Length == 0)
801+
if (uninitializedProperties.Count == 0)
802+
return;
803+
804+
var updateLazyProperties = fetchAllProperties
805+
? uninitializedProperties.ToArray()
806+
: fetchLazyProperties.Intersect(uninitializedProperties).ToArray();
807+
if (updateLazyProperties.Length == 0)
803808
{
804809
return; // No new lazy properites were loaded
805810
}
@@ -815,7 +820,7 @@ private async Task UpdateLazyPropertiesFromResultSetAsync(DbDataReader rs, int i
815820
? EntityAliases[i].SuffixedPropertyAliases
816821
: GetSubclassEntityAliases(i, persister);
817822

818-
if (!await (persister.InitializeLazyPropertiesAsync(rs, id, obj, cols, updateLazyProperties, fetchAllProperties, session, cancellationToken)).ConfigureAwait(false))
823+
if (!await (persister.InitializeLazyPropertiesAsync(rs, id, obj, cols, updateLazyProperties, false, session, cancellationToken)).ConfigureAwait(false))
819824
{
820825
return;
821826
}

src/NHibernate/Loader/Loader.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,8 +1204,13 @@ private void UpdateLazyPropertiesFromResultSet(DbDataReader rs, int i, object ob
12041204
? persister.EntityMetamodel.BytecodeEnhancementMetadata.GetUninitializedLazyProperties(entry.LoadedState)
12051205
: persister.EntityMetamodel.BytecodeEnhancementMetadata.GetUninitializedLazyProperties(obj);
12061206

1207-
var updateLazyProperties = fetchLazyProperties?.Intersect(uninitializedProperties).ToArray();
1208-
if (updateLazyProperties?.Length == 0)
1207+
if (uninitializedProperties.Count == 0)
1208+
return;
1209+
1210+
var updateLazyProperties = fetchAllProperties
1211+
? uninitializedProperties.ToArray()
1212+
: fetchLazyProperties.Intersect(uninitializedProperties).ToArray();
1213+
if (updateLazyProperties.Length == 0)
12091214
{
12101215
return; // No new lazy properites were loaded
12111216
}
@@ -1221,7 +1226,7 @@ private void UpdateLazyPropertiesFromResultSet(DbDataReader rs, int i, object ob
12211226
? EntityAliases[i].SuffixedPropertyAliases
12221227
: GetSubclassEntityAliases(i, persister);
12231228

1224-
if (!persister.InitializeLazyProperties(rs, id, obj, cols, updateLazyProperties, fetchAllProperties, session))
1229+
if (!persister.InitializeLazyProperties(rs, id, obj, cols, updateLazyProperties, false, session))
12251230
{
12261231
return;
12271232
}

src/NHibernate/Tuple/Entity/PocoEntityTuplizer.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using NHibernate.Util;
1313
using System.Runtime.Serialization;
1414
using NHibernate.Bytecode.Lightweight;
15+
using NHibernate.Intercept;
1516

1617
namespace NHibernate.Tuple.Entity
1718
{
@@ -306,6 +307,16 @@ public override bool IsLifecycleImplementor
306307

307308
public override void SetPropertyValue(object entity, int i, object value)
308309
{
310+
// If there is no property setter we need to manually intercept value for proper lazy property handling.
311+
if (IsInstrumented && setters[i].PropertyName == null)
312+
{
313+
IFieldInterceptor interceptor = _enhancementMetadata.ExtractInterceptor(entity);
314+
if (interceptor != null)
315+
{
316+
value = interceptor.Intercept(entity, EntityMetamodel.PropertyNames[i], value, true);
317+
}
318+
}
319+
309320
if (isBytecodeProviderImpl && optimizer?.AccessOptimizer != null)
310321
{
311322
optimizer.AccessOptimizer.SetPropertyValue(entity, i, value);

0 commit comments

Comments
 (0)