diff --git a/src/NHibernate.Test/Async/GhostProperty/GhostPropertyFixture.cs b/src/NHibernate.Test/Async/GhostProperty/GhostPropertyFixture.cs index 12ab309a529..281ed163c32 100644 --- a/src/NHibernate.Test/Async/GhostProperty/GhostPropertyFixture.cs +++ b/src/NHibernate.Test/Async/GhostProperty/GhostPropertyFixture.cs @@ -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()))[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()); + 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(); + query.Add(Criterion.Restrictions.Eq("Id", 1)); + order = (await (query.ListAsync()))[0]; + s.Disconnect(); + + Assert.Throws(typeof(LazyInitializationException), () => { var y = order.Payment; }); + + s.Reconnect(); + + // ... then join-fetch the related payment + var query2 = s.CreateCriteria(); + 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")); + } } } diff --git a/src/NHibernate.Test/GhostProperty/GhostPropertyFixture.cs b/src/NHibernate.Test/GhostProperty/GhostPropertyFixture.cs index 13a3c6e0e7b..70e1e21613e 100644 --- a/src/NHibernate.Test/GhostProperty/GhostPropertyFixture.cs +++ b/src/NHibernate.Test/GhostProperty/GhostPropertyFixture.cs @@ -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()[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(); + 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(); + query.Add(Criterion.Restrictions.Eq("Id", 1)); + order = query.List()[0]; + s.Disconnect(); + + Assert.Throws(typeof(LazyInitializationException), () => { var y = order.Payment; }); + + s.Reconnect(); + + // ... then join-fetch the related payment + var query2 = s.CreateCriteria(); + 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")); + } } } diff --git a/src/NHibernate.Test/GhostProperty/Mappings.hbm.xml b/src/NHibernate.Test/GhostProperty/Mappings.hbm.xml index 2594f4c5afa..6790652371b 100644 --- a/src/NHibernate.Test/GhostProperty/Mappings.hbm.xml +++ b/src/NHibernate.Test/GhostProperty/Mappings.hbm.xml @@ -19,6 +19,7 @@ + diff --git a/src/NHibernate.Test/GhostProperty/Order.cs b/src/NHibernate.Test/GhostProperty/Order.cs index a0ef5e9a01b..99c0465c1cc 100644 --- a/src/NHibernate.Test/GhostProperty/Order.cs +++ b/src/NHibernate.Test/GhostProperty/Order.cs @@ -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 { } -} \ No newline at end of file +} diff --git a/src/NHibernate/Intercept/AbstractFieldInterceptor.cs b/src/NHibernate/Intercept/AbstractFieldInterceptor.cs index 87ede553e0a..898805360d9 100644 --- a/src/NHibernate/Intercept/AbstractFieldInterceptor.cs +++ b/src/NHibernate/Intercept/AbstractFieldInterceptor.cs @@ -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) @@ -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)