Skip to content

Commit ac5a708

Browse files
author
Thomas Alken
committed
Bugfix for Issue 3622: ISession.Refresh does not update lazy properties
1 parent f5a7a1f commit ac5a708

File tree

6 files changed

+50
-13
lines changed

6 files changed

+50
-13
lines changed

src/NHibernate.Test/FetchLazyProperties/FetchLazyPropertiesFixture.cs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,6 +1076,41 @@ void AssertPersons(List<Person> results, bool fetched)
10761076
}
10771077
}
10781078

1079+
[Test]
1080+
public void TestRefreshRemovesLazyLoadedProperties()
1081+
{
1082+
using (var outerSession = OpenSession())
1083+
{
1084+
const string query = "from Person fetch Image where Id = 1";
1085+
const string namePostFix = "_MODIFIED";
1086+
const int imageLength = 4711;
1087+
1088+
Person outerPerson = outerSession.CreateQuery(query).UniqueResult<Person>();
1089+
1090+
Assert.That(outerPerson.Name.EndsWith(namePostFix), Is.False); // Normal property
1091+
Assert.That(outerPerson.Image.Length, Is.EqualTo(1)); // Lazy Property
1092+
1093+
// Changing the properties of the person in a different sessions
1094+
using (var innerSession = OpenSession())
1095+
{
1096+
var transaction = innerSession.BeginTransaction();
1097+
1098+
Person innerPerson = innerSession.CreateQuery(query).UniqueResult<Person>();
1099+
innerPerson.Image = new byte[imageLength];
1100+
innerPerson.Name += namePostFix;
1101+
innerSession.Update(innerPerson);
1102+
1103+
transaction.Commit();
1104+
}
1105+
1106+
// Refreshing the person in the outer session
1107+
outerSession.Refresh(outerPerson);
1108+
1109+
Assert.That(outerPerson.Name.EndsWith(namePostFix), Is.True); // Value has changed
1110+
Assert.That(outerPerson.Image.Length, Is.EqualTo(imageLength)); // This is still the old value
1111+
}
1112+
}
1113+
10791114
private static Person GeneratePerson(int i, Person bestFriend)
10801115
{
10811116
return new Person

src/NHibernate/Engine/EntityEntry.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,7 @@ public object RowId
200200
{
201201
get { return rowId; }
202202
}
203-
204-
// Since 5.3
205-
[Obsolete("This property is not used and will be removed in a future version.")]
203+
206204
public bool LoadedWithLazyPropertiesUnfetched
207205
{
208206
get { return loadedWithLazyPropertiesUnfetched; }

src/NHibernate/Engine/IPersistenceContext.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,6 @@ EntityEntry AddEntity(object entity, Status status, object[] loadedState, Entity
173173
/// Generates an appropriate EntityEntry instance and adds it
174174
/// to the event source's internal caches.
175175
/// </summary>
176-
// Since 5.3
177-
[Obsolete("Use the AddEntry extension method instead")]
178176
EntityEntry AddEntry(object entity, Status status, object[] loadedState, object rowId, object id, object version,
179177
LockMode lockMode, bool existsInDatabase, IEntityPersister persister, bool disableVersionIncrement,
180178
bool lazyPropertiesAreUnfetched);

src/NHibernate/Engine/TwoPhaseLoad.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ public static partial class TwoPhaseLoad
3030
/// to resolve any associations yet, because there might be other entities waiting to be
3131
/// read from the JDBC result set we are currently processing
3232
/// </summary>
33-
// Since 5.3
34-
[Obsolete("Use the overload without lazyPropertiesAreUnfetched parameter instead")]
3533
public static void PostHydrate(IEntityPersister persister, object id, object[] values, object rowId, object obj, LockMode lockMode, bool lazyPropertiesAreUnfetched, ISessionImplementor session)
3634
{
3735
object version = Versioning.GetVersion(values, persister);

src/NHibernate/Loader/Loader.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,7 +1147,8 @@ private object InstanceNotYetLoaded(DbDataReader dr, int i, ILoadable persister,
11471147

11481148
ILoadable concretePersister = GetConcretePersister(dr, i, persister, key.Identifier, session);
11491149

1150-
if (optionalObjectKey != null && key.Equals(optionalObjectKey))
1150+
bool useOptionalObject = optionalObjectKey != null && key.Equals(optionalObjectKey);
1151+
if (useOptionalObject)
11511152
{
11521153
// its the given optional object
11531154
obj = optionalObject;
@@ -1163,8 +1164,8 @@ private object InstanceNotYetLoaded(DbDataReader dr, int i, ILoadable persister,
11631164
// (but don't yet initialize the object itself)
11641165
// note that we acquired LockMode.READ even if it was not requested
11651166
LockMode acquiredLockMode = lockMode == LockMode.None ? LockMode.Read : lockMode;
1166-
LoadFromResultSet(dr, i, obj, concretePersister, key, acquiredLockMode, persister, session);
1167-
1167+
LoadFromResultSet(dr, i, obj, concretePersister, key, acquiredLockMode, persister, session, useOptionalObject);
1168+
11681169
// materialize associations (and initialize the object) later
11691170
hydratedObjects.Add(obj);
11701171

@@ -1291,7 +1292,7 @@ internal static void UpdateCacheForEntity(
12911292
/// </summary>
12921293
private void LoadFromResultSet(DbDataReader rs, int i, object obj, ILoadable persister, EntityKey key,
12931294
LockMode lockMode, ILoadable rootPersister,
1294-
ISessionImplementor session)
1295+
ISessionImplementor session, bool lazyPropertiesAreUnfetched)
12951296
{
12961297
object id = key.Identifier;
12971298

@@ -1316,7 +1317,7 @@ private void LoadFromResultSet(DbDataReader rs, int i, object obj, ILoadable per
13161317

13171318
object rowId = persister.HasRowId ? rs[EntityAliases[i].RowIdAlias] : null;
13181319

1319-
TwoPhaseLoad.PostHydrate(persister, id, values, rowId, obj, lockMode, session);
1320+
TwoPhaseLoad.PostHydrate(persister, id, values, rowId, obj, lockMode, lazyPropertiesAreUnfetched, session);
13201321
}
13211322

13221323
private string[][] GetSubclassEntityAliases(int i, ILoadable persister)

src/NHibernate/Tuple/Entity/PocoEntityTuplizer.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ public override void AfterInitialize(object entity, ISessionImplementor session)
226226
if (IsInstrumented)
227227
{
228228
var interceptor = _enhancementMetadata.ExtractInterceptor(entity);
229-
if (interceptor == null)
229+
if (interceptor == null || HasAnyInitializedLazyProperty(entity, session))
230230
{
231231
interceptor = _enhancementMetadata.InjectInterceptor(entity, session);
232232
}
@@ -239,6 +239,13 @@ public override void AfterInitialize(object entity, ISessionImplementor session)
239239
}
240240
}
241241

242+
private static bool HasAnyInitializedLazyProperty(object entity, ISessionImplementor session)
243+
{
244+
IPersistenceContext persistenceContext = session.PersistenceContext;
245+
EntityEntry entityEntry = persistenceContext.GetEntry(entity);
246+
return entityEntry.LoadedWithLazyPropertiesUnfetched;
247+
}
248+
242249
public override object GetPropertyValue(object entity, int i)
243250
{
244251
if (isBytecodeProviderImpl && optimizer?.AccessOptimizer != null)

0 commit comments

Comments
 (0)