Skip to content

Commit ce73fc0

Browse files
maca88fredericDelaporte
authored andcommitted
Skip initialization of lazy properties when setting one (#1943)
1 parent 4d887d8 commit ce73fc0

19 files changed

+474
-27
lines changed

src/NHibernate.Test/Async/GhostProperty/GhostPropertyFixture.cs

+16-1
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,21 @@ public async Task WhenGetThenLoadOnlyNoLazyPlainPropertiesAsync()
167167
}
168168
Assert.That(NHibernateUtil.IsPropertyInitialized(order, "ALazyProperty"), Is.True);
169169
}
170-
}
170+
}
171+
172+
[Test]
173+
public async Task AcceptPropertySetWithTransientObjectAsync()
174+
{
175+
Order order;
176+
using (var s = OpenSession())
177+
{
178+
order = await (s.GetAsync<Order>(1));
179+
}
180+
181+
var newPayment = new WireTransfer();
182+
order.Payment = newPayment;
183+
184+
Assert.That(order.Payment, Is.EqualTo(newPayment));
185+
}
171186
}
172187
}

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

+97
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,17 @@
1010

1111
using System.Collections;
1212
using System.Linq;
13+
using NHibernate.Cfg;
1314
using NHibernate.Intercept;
1415
using NHibernate.Tuple.Entity;
1516
using NUnit.Framework;
17+
using NUnit.Framework.Constraints;
1618
using NHibernate.Linq;
1719

1820
namespace NHibernate.Test.LazyProperty
1921
{
2022
using System.Threading.Tasks;
23+
using System.Threading;
2124
[TestFixture]
2225
public class LazyPropertyFixtureAsync : TestCase
2326
{
@@ -43,6 +46,11 @@ protected override DebugSessionFactory BuildSessionFactory()
4346
}
4447
}
4548

49+
protected override void Configure(Configuration configuration)
50+
{
51+
configuration.SetProperty(Environment.GenerateStatistics, "true");
52+
}
53+
4654
protected override void OnSetUp()
4755
{
4856
Assert.That(
@@ -58,6 +66,7 @@ protected override void OnSetUp()
5866
Name = "some name",
5967
Id = 1,
6068
ALotOfText = "a lot of text ...",
69+
Image = new byte[10],
6170
FieldInterceptor = "Why not that name?"
6271
});
6372
tx.Commit();
@@ -122,6 +131,94 @@ public async Task CanGetValueForLazyPropertyAsync()
122131
}
123132
}
124133

134+
[Test]
135+
public async Task CanSetValueForLazyPropertyAsync()
136+
{
137+
Book book;
138+
using (ISession s = OpenSession())
139+
{
140+
book = await (s.GetAsync<Book>(1));
141+
}
142+
143+
book.ALotOfText = "text";
144+
145+
Assert.That(book.ALotOfText, Is.EqualTo("text"));
146+
Assert.That(NHibernateUtil.IsPropertyInitialized(book, "ALotOfText"), Is.True);
147+
}
148+
149+
[TestCase(false)]
150+
[TestCase(true)]
151+
public async Task CanUpdateValueForLazyPropertyAsync(bool initializeAfterSet, CancellationToken cancellationToken = default(CancellationToken))
152+
{
153+
Book book;
154+
using (var s = OpenSession())
155+
using (var tx = s.BeginTransaction())
156+
{
157+
book = await (s.GetAsync<Book>(1, cancellationToken));
158+
book.ALotOfText = "update-text";
159+
if (initializeAfterSet)
160+
{
161+
var image = book.Image;
162+
}
163+
164+
await (tx.CommitAsync(cancellationToken));
165+
}
166+
167+
using (var s = OpenSession())
168+
{
169+
book = await (s.GetAsync<Book>(1, cancellationToken));
170+
var text = book.ALotOfText;
171+
}
172+
173+
Assert.That(NHibernateUtil.IsPropertyInitialized(book, "ALotOfText"), Is.True);
174+
Assert.That(NHibernateUtil.IsPropertyInitialized(book, "Image"), Is.True);
175+
Assert.That(book.ALotOfText, Is.EqualTo("update-text"));
176+
Assert.That(book.Image, Has.Length.EqualTo(10));
177+
}
178+
179+
[TestCase(false)]
180+
[TestCase(true)]
181+
public async Task UpdateValueForLazyPropertyToSameValueAsync(bool initializeAfterSet, CancellationToken cancellationToken = default(CancellationToken))
182+
{
183+
Book book;
184+
string text;
185+
186+
using (var s = OpenSession())
187+
{
188+
book = await (s.GetAsync<Book>(1, cancellationToken));
189+
text = book.ALotOfText;
190+
}
191+
192+
Sfi.Statistics.Clear();
193+
194+
using (var s = OpenSession())
195+
using (var tx = s.BeginTransaction())
196+
{
197+
book = await (s.GetAsync<Book>(1, cancellationToken));
198+
book.ALotOfText = text;
199+
if (initializeAfterSet)
200+
{
201+
var image = book.Image;
202+
}
203+
204+
await (tx.CommitAsync(cancellationToken));
205+
}
206+
207+
Assert.That(Sfi.Statistics.EntityUpdateCount, Is.EqualTo(initializeAfterSet ? 0 : 1));
208+
Assert.That(NHibernateUtil.IsPropertyInitialized(book, "ALotOfText"), Is.True);
209+
Assert.That(NHibernateUtil.IsPropertyInitialized(book, "Image"), initializeAfterSet ? (Constraint) Is.True : Is.False);
210+
Assert.That(book.ALotOfText, Is.EqualTo(text));
211+
212+
using (var s = OpenSession())
213+
{
214+
book = await (s.GetAsync<Book>(1, cancellationToken));
215+
text = book.ALotOfText;
216+
}
217+
218+
Assert.That(book.Image, Has.Length.EqualTo(10));
219+
Assert.That(book.ALotOfText, Is.EqualTo(text));
220+
}
221+
125222
[Test]
126223
public async Task CanGetValueForNonLazyPropertyAsync()
127224
{

src/NHibernate.Test/GhostProperty/GhostPropertyFixture.cs

+16-1
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,21 @@ public void WhenGetThenLoadOnlyNoLazyPlainProperties()
162162
}
163163
Assert.That(NHibernateUtil.IsPropertyInitialized(order, "ALazyProperty"), Is.True);
164164
}
165-
}
165+
}
166+
167+
[Test]
168+
public void AcceptPropertySetWithTransientObject()
169+
{
170+
Order order;
171+
using (var s = OpenSession())
172+
{
173+
order = s.Get<Order>(1);
174+
}
175+
176+
var newPayment = new WireTransfer();
177+
order.Payment = newPayment;
178+
179+
Assert.That(order.Payment, Is.EqualTo(newPayment));
180+
}
166181
}
167182
}

src/NHibernate.Test/LazyProperty/Book.cs

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ public virtual string ALotOfText
1313
set { _aLotOfText = value; }
1414
}
1515

16+
public virtual byte[] Image { get; set; }
17+
1618
public virtual string FieldInterceptor { get; set; }
1719
}
1820
}

src/NHibernate.Test/LazyProperty/LazyPropertyFixture.cs

+96
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
using System.Collections;
22
using System.Linq;
3+
using NHibernate.Cfg;
34
using NHibernate.Intercept;
45
using NHibernate.Tuple.Entity;
56
using NUnit.Framework;
7+
using NUnit.Framework.Constraints;
68

79
namespace NHibernate.Test.LazyProperty
810
{
@@ -31,6 +33,11 @@ protected override DebugSessionFactory BuildSessionFactory()
3133
}
3234
}
3335

36+
protected override void Configure(Configuration configuration)
37+
{
38+
configuration.SetProperty(Environment.GenerateStatistics, "true");
39+
}
40+
3441
protected override void OnSetUp()
3542
{
3643
Assert.That(
@@ -46,6 +53,7 @@ protected override void OnSetUp()
4653
Name = "some name",
4754
Id = 1,
4855
ALotOfText = "a lot of text ...",
56+
Image = new byte[10],
4957
FieldInterceptor = "Why not that name?"
5058
});
5159
tx.Commit();
@@ -116,6 +124,94 @@ public void CanGetValueForLazyProperty()
116124
}
117125
}
118126

127+
[Test]
128+
public void CanSetValueForLazyProperty()
129+
{
130+
Book book;
131+
using (ISession s = OpenSession())
132+
{
133+
book = s.Get<Book>(1);
134+
}
135+
136+
book.ALotOfText = "text";
137+
138+
Assert.That(book.ALotOfText, Is.EqualTo("text"));
139+
Assert.That(NHibernateUtil.IsPropertyInitialized(book, "ALotOfText"), Is.True);
140+
}
141+
142+
[TestCase(false)]
143+
[TestCase(true)]
144+
public void CanUpdateValueForLazyProperty(bool initializeAfterSet)
145+
{
146+
Book book;
147+
using (var s = OpenSession())
148+
using (var tx = s.BeginTransaction())
149+
{
150+
book = s.Get<Book>(1);
151+
book.ALotOfText = "update-text";
152+
if (initializeAfterSet)
153+
{
154+
var image = book.Image;
155+
}
156+
157+
tx.Commit();
158+
}
159+
160+
using (var s = OpenSession())
161+
{
162+
book = s.Get<Book>(1);
163+
var text = book.ALotOfText;
164+
}
165+
166+
Assert.That(NHibernateUtil.IsPropertyInitialized(book, "ALotOfText"), Is.True);
167+
Assert.That(NHibernateUtil.IsPropertyInitialized(book, "Image"), Is.True);
168+
Assert.That(book.ALotOfText, Is.EqualTo("update-text"));
169+
Assert.That(book.Image, Has.Length.EqualTo(10));
170+
}
171+
172+
[TestCase(false)]
173+
[TestCase(true)]
174+
public void UpdateValueForLazyPropertyToSameValue(bool initializeAfterSet)
175+
{
176+
Book book;
177+
string text;
178+
179+
using (var s = OpenSession())
180+
{
181+
book = s.Get<Book>(1);
182+
text = book.ALotOfText;
183+
}
184+
185+
Sfi.Statistics.Clear();
186+
187+
using (var s = OpenSession())
188+
using (var tx = s.BeginTransaction())
189+
{
190+
book = s.Get<Book>(1);
191+
book.ALotOfText = text;
192+
if (initializeAfterSet)
193+
{
194+
var image = book.Image;
195+
}
196+
197+
tx.Commit();
198+
}
199+
200+
Assert.That(Sfi.Statistics.EntityUpdateCount, Is.EqualTo(initializeAfterSet ? 0 : 1));
201+
Assert.That(NHibernateUtil.IsPropertyInitialized(book, "ALotOfText"), Is.True);
202+
Assert.That(NHibernateUtil.IsPropertyInitialized(book, "Image"), initializeAfterSet ? (Constraint) Is.True : Is.False);
203+
Assert.That(book.ALotOfText, Is.EqualTo(text));
204+
205+
using (var s = OpenSession())
206+
{
207+
book = s.Get<Book>(1);
208+
text = book.ALotOfText;
209+
}
210+
211+
Assert.That(book.Image, Has.Length.EqualTo(10));
212+
Assert.That(book.ALotOfText, Is.EqualTo(text));
213+
}
214+
119215
[Test]
120216
public void CanGetValueForNonLazyProperty()
121217
{

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

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
</id>
1010
<property name="Name" />
1111
<property name="ALotOfText" lazy="true" />
12+
<property name="Image" lazy="true" />
1213
<property name="FieldInterceptor" />
1314
</class>
1415

src/NHibernate/Async/Engine/Cascade.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,12 @@ public async Task CascadeOnAsync(IEntityPersister persister, object parent, obje
6060

6161
IType[] types = persister.PropertyTypes;
6262
CascadeStyle[] cascadeStyles = persister.PropertyCascadeStyles;
63-
bool hasUninitializedLazyProperties = persister.HasUninitializedLazyProperties(parent);
63+
var uninitializedLazyProperties = persister.GetUninitializedLazyProperties(parent);
6464
for (int i = 0; i < types.Length; i++)
6565
{
6666
CascadeStyle style = cascadeStyles[i];
6767
string propertyName = persister.PropertyNames[i];
68-
if (hasUninitializedLazyProperties && persister.PropertyLaziness[i] && !action.PerformOnLazyProperty)
68+
if (uninitializedLazyProperties.Contains(propertyName) && persister.PropertyLaziness[i] && !action.PerformOnLazyProperty)
6969
{
7070
//do nothing to avoid a lazy property initialization
7171
continue;

src/NHibernate/Async/Persister/Entity/AbstractEntityPersister.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -876,8 +876,8 @@ public async Task UpdateAsync(object id, object[] fields, int[] dirtyFields, boo
876876
// in the process of being deleted.
877877
if (entry == null && !IsMutable)
878878
throw new InvalidOperationException("Updating immutable entity that is not in session yet!");
879-
880-
if (entityMetamodel.IsDynamicUpdate && dirtyFields != null)
879+
880+
if (dirtyFields != null && (entityMetamodel.IsDynamicUpdate || HasDirtyLazyProperties(dirtyFields, obj)))
881881
{
882882
// For the case of dynamic-update="true", we need to generate the UPDATE SQL
883883
propsToUpdate = GetPropertiesToUpdate(dirtyFields, hasDirtyCollection);

src/NHibernate/Async/Persister/Entity/IEntityPersister.cs

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
//------------------------------------------------------------------------------
99

1010

11+
using System;
1112
using NHibernate.Cache;
1213
using NHibernate.Cache.Entry;
1314
using NHibernate.Engine;
@@ -16,6 +17,9 @@
1617
using NHibernate.Tuple.Entity;
1718
using NHibernate.Type;
1819
using System.Collections;
20+
using System.Collections.Generic;
21+
using NHibernate.Intercept;
22+
using NHibernate.Util;
1923

2024
namespace NHibernate.Persister.Entity
2125
{

src/NHibernate/Engine/Cascade.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,12 @@ public void CascadeOn(IEntityPersister persister, object parent, object anything
113113

114114
IType[] types = persister.PropertyTypes;
115115
CascadeStyle[] cascadeStyles = persister.PropertyCascadeStyles;
116-
bool hasUninitializedLazyProperties = persister.HasUninitializedLazyProperties(parent);
116+
var uninitializedLazyProperties = persister.GetUninitializedLazyProperties(parent);
117117
for (int i = 0; i < types.Length; i++)
118118
{
119119
CascadeStyle style = cascadeStyles[i];
120120
string propertyName = persister.PropertyNames[i];
121-
if (hasUninitializedLazyProperties && persister.PropertyLaziness[i] && !action.PerformOnLazyProperty)
121+
if (uninitializedLazyProperties.Contains(propertyName) && persister.PropertyLaziness[i] && !action.PerformOnLazyProperty)
122122
{
123123
//do nothing to avoid a lazy property initialization
124124
continue;

0 commit comments

Comments
 (0)