Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix getting of initialized proxies for no-proxy associations outside of session scope #3347

Merged
merged 4 commits into from
Jul 4, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions src/NHibernate.Test/Async/GhostProperty/GhostPropertyFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -253,5 +253,54 @@ public async Task WillFetchJoinInSingleHqlQueryAsync()

Assert.DoesNotThrow(() => { var x = order.Payment; });
}

[Test(Description = "GH-1267(NH-3047)")]
public async Task WillFetchJoinInAdditionalHqlQueryAsync()
{
Order order = null;

// load the order...
ISession s = OpenSession();
order = (await (s.CreateQuery("from Order o where o.Id = 1").ListAsync<Order>()))[0];
s.Disconnect();

Assert.Throws(typeof(LazyInitializationException), () => { var y = order.Payment; });

s.Reconnect();
// ... then join-fetch the related payment
await (s.CreateQuery("from Order o left join fetch o.Payment where o.Id = 1").ListAsync<Order>());
s.Close();

Assert.DoesNotThrow(() => { var x = order.Payment; });
Assert.That(order.Payment.Type, Is.EqualTo("WT"));
}

[Test(Description = "GH-1267(NH-3047)")]
public async Task WillFetchJoinWithCriteriaAsync()
{
Order order = null;

// load the order...
ISession s = OpenSession();

var query = s.CreateCriteria<Order>();
query.Add(Criterion.Restrictions.Eq("Id", 1));
order = (await (query.ListAsync<Order>()))[0];
s.Disconnect();

Assert.Throws(typeof(LazyInitializationException), () => { var y = order.Payment; });

s.Reconnect();

// ... then join-fetch the related payment
var query2 = s.CreateCriteria<Order>();
query2.Add(Criterion.Restrictions.Eq("Id", 1));
query2.Fetch(SelectMode.Fetch, "Payment");
await (query2.ListAsync());
s.Close();

Assert.DoesNotThrow(() => { var x = order.Payment; });
Assert.That(order.Payment.Type, Is.EqualTo("WT"));
}
}
}
49 changes: 49 additions & 0 deletions src/NHibernate.Test/GhostProperty/GhostPropertyFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -260,5 +260,54 @@ public void WillFetchJoinInSingleHqlQuery()

Assert.DoesNotThrow(() => { var x = order.Payment; });
}

[Test(Description = "GH-1267(NH-3047)")]
public void WillFetchJoinInAdditionalHqlQuery()
{
Order order = null;

// load the order...
ISession s = OpenSession();
order = s.CreateQuery("from Order o where o.Id = 1").List<Order>()[0];
s.Disconnect();

Assert.Throws(typeof(LazyInitializationException), () => { var y = order.Payment; });

s.Reconnect();
// ... then join-fetch the related payment
s.CreateQuery("from Order o left join fetch o.Payment where o.Id = 1").List<Order>();
s.Close();

Assert.DoesNotThrow(() => { var x = order.Payment; });
Assert.That(order.Payment.Type, Is.EqualTo("WT"));
}

[Test(Description = "GH-1267(NH-3047)")]
public void WillFetchJoinWithCriteria()
{
Order order = null;

// load the order...
ISession s = OpenSession();

var query = s.CreateCriteria<Order>();
query.Add(Criterion.Restrictions.Eq("Id", 1));
order = query.List<Order>()[0];
s.Disconnect();

Assert.Throws(typeof(LazyInitializationException), () => { var y = order.Payment; });

s.Reconnect();

// ... then join-fetch the related payment
var query2 = s.CreateCriteria<Order>();
query2.Add(Criterion.Restrictions.Eq("Id", 1));
query2.Fetch(SelectMode.Fetch, "Payment");
query2.List();
s.Close();

Assert.DoesNotThrow(() => { var x = order.Payment; });
Assert.That(order.Payment.Type, Is.EqualTo("WT"));
}
}
}
1 change: 1 addition & 0 deletions src/NHibernate.Test/GhostProperty/Mappings.hbm.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<generator class="assigned" />
</id>
<discriminator column="Type" type="System.String"/>
<property name="Type" column="Type" insert="false" update="false" />
<subclass name="WireTransfer" discriminator-value="WT">

</subclass>
Expand Down
3 changes: 2 additions & 1 deletion src/NHibernate.Test/GhostProperty/Order.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ public virtual Payment Payment
public abstract class Payment
{
public virtual int Id { get; set; }
public virtual string Type { get; set; }
}

public class WireTransfer : Payment{}
public class CreditCard : Payment { }
}
}
48 changes: 26 additions & 22 deletions src/NHibernate/Intercept/AbstractFieldInterceptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,39 +128,43 @@ public object Intercept(object target, string fieldName, object value, bool sett
return InvokeImplementation;
}

if (IsInitializedField(fieldName))
if (IsUninitializedProperty(fieldName))
{
return value;
}
if (session == null)
{
throw new LazyInitializationException(EntityName, null, string.Format("entity with lazy properties is not associated with a session. entity-name:'{0}' property:'{1}'", EntityName, fieldName));
}
if (!session.IsOpen || !session.IsConnected)
{
throw new LazyInitializationException(EntityName, null, string.Format("session is not connected. entity-name:'{0}' property:'{1}'", EntityName, fieldName));
}

if (session == null)
{
throw new LazyInitializationException(EntityName, null, string.Format("entity with lazy properties is not associated with a session. entity-name:'{0}' property:'{1}'", EntityName, fieldName));
}
if (!session.IsOpen || !session.IsConnected)
{
throw new LazyInitializationException(EntityName, null, string.Format("session is not connected. entity-name:'{0}' property:'{1}'", EntityName, fieldName));
return InitializeField(fieldName, target);
}

if (IsUninitializedProperty(fieldName))
if (!IsUninitializedAssociation(fieldName))
{
return InitializeField(fieldName, target);
return value;
}

if (value.IsProxy() && IsUninitializedAssociation(fieldName))
if (value is INHibernateProxy nhproxy)
{
var nhproxy = value as INHibernateProxy;
value = InitializeOrGetAssociation(nhproxy, fieldName);
// Set the property value in order to be accessible when the session is closed
var persister = session.Factory.GetEntityPersister(entityName);
persister.SetPropertyValue(
target,
persister.EntityMetamodel.BytecodeEnhancementMetadata.UnwrapProxyPropertiesMetadata.GetUnwrapProxyPropertyIndex(fieldName),
value);
if (session?.Factory.IsClosed == false)
{
// Set the property value in order to be accessible when the session is closed
var persister = session.Factory.GetEntityPersister(entityName);
persister.SetPropertyValue(
target,
persister.EntityMetamodel.GetPropertyIndex(fieldName),
value);
}

return value;
}
return InvokeImplementation;

loadedUnwrapProxyFieldNames.Add(fieldName);
return value;
}

private bool IsUninitializedAssociation(string fieldName)
Expand All @@ -181,7 +185,7 @@ private object InitializeOrGetAssociation(INHibernateProxy value, string fieldNa
value.HibernateLazyInitializer.Unwrap = true; // means that future Load/Get from the session will get the implementation
loadedUnwrapProxyFieldNames.Add(fieldName);
}
return value.HibernateLazyInitializer.GetImplementation(session);
return value.HibernateLazyInitializer.GetImplementation();
}

private object InitializeField(string fieldName, object target)
Expand Down