@@ -397,6 +397,7 @@ public abstract class AbstractEntityPersister
397
397
private final int [] lazyPropertyNumbers ;
398
398
private final Type [] lazyPropertyTypes ;
399
399
private final String [][] lazyPropertyColumnAliases ;
400
+ private final Set <String > nonLazyPropertyNames ;
400
401
401
402
//information about all properties in class hierarchy
402
403
private final String [] subclassPropertyNameClosure ;
@@ -495,6 +496,7 @@ public abstract class AbstractEntityPersister
495
496
private final boolean implementsLifecycle ;
496
497
497
498
private List <UniqueKeyEntry > uniqueKeyEntries = null ; //lazily initialized
499
+ private HashMap <String ,SingleIdArrayLoadPlan > nonLazyPropertyLoadPlansByName ;
498
500
499
501
@ Deprecated (since = "6.0" )
500
502
public AbstractEntityPersister (
@@ -645,6 +647,7 @@ public AbstractEntityPersister(
645
647
propertyColumnUpdateable = new boolean [hydrateSpan ][];
646
648
propertyColumnInsertable = new boolean [hydrateSpan ][];
647
649
sharedColumnNames = new HashSet <>();
650
+ nonLazyPropertyNames = new HashSet <>();
648
651
649
652
final HashSet <Property > thisClassProperties = new HashSet <>();
650
653
final ArrayList <String > lazyNames = new ArrayList <>();
@@ -710,6 +713,9 @@ public AbstractEntityPersister(
710
713
lazyTypes .add ( prop .getValue ().getType () );
711
714
lazyColAliases .add ( colAliases );
712
715
}
716
+ else {
717
+ nonLazyPropertyNames .add ( prop .getName () );
718
+ }
713
719
714
720
propertyColumnUpdateable [i ] = prop .getValue ().getColumnUpdateability ();
715
721
propertyColumnInsertable [i ] = prop .getValue ().getColumnInsertability ();
@@ -1330,6 +1336,10 @@ private SingleIdArrayLoadPlan createLazyLoadPlan(List<LazyAttributeDescriptor> f
1330
1336
partsToSelect .add ( getAttributeMapping ( getSubclassPropertyIndex ( lazyAttributeDescriptor .getName () ) ) );
1331
1337
}
1332
1338
1339
+ return createLazyLoanPlan ( partsToSelect );
1340
+ }
1341
+
1342
+ private SingleIdArrayLoadPlan createLazyLoanPlan (List <ModelPart > partsToSelect ) {
1333
1343
if ( partsToSelect .isEmpty () ) {
1334
1344
// only one-to-one is lazily fetched
1335
1345
return null ;
@@ -1655,75 +1665,117 @@ protected Object initializeLazyPropertiesFromDatastore(
1655
1665
final EntityEntry entry ,
1656
1666
final String fieldName ,
1657
1667
final SharedSessionContractImplementor session ) {
1658
-
1659
- if ( !hasLazyProperties () ) {
1660
- throw new AssertionFailure ( "no lazy properties" );
1668
+ if ( nonLazyPropertyNames .contains ( fieldName ) ) {
1669
+ // An eager property can be lazy because of an applied EntityGraph
1670
+ final List <ModelPart > partsToSelect = new ArrayList <>(1 );
1671
+ int propertyIndex = getPropertyIndex ( fieldName );
1672
+ partsToSelect .add ( getAttributeMapping ( propertyIndex ) );
1673
+ SingleIdArrayLoadPlan lazyLoanPlan ;
1674
+ if ( nonLazyPropertyLoadPlansByName == null ) {
1675
+ nonLazyPropertyLoadPlansByName = new HashMap <>();
1676
+ lazyLoanPlan = createLazyLoanPlan ( partsToSelect );
1677
+ ;
1678
+ nonLazyPropertyLoadPlansByName .put ( fieldName , lazyLoanPlan );
1679
+ }
1680
+ else {
1681
+ lazyLoanPlan = nonLazyPropertyLoadPlansByName .get ( fieldName );
1682
+ if ( lazyLoanPlan == null ) {
1683
+ lazyLoanPlan = createLazyLoanPlan ( partsToSelect );
1684
+ ;
1685
+ nonLazyPropertyLoadPlansByName .put ( fieldName , lazyLoanPlan );
1686
+ }
1687
+ }
1688
+ try {
1689
+ final Object [] values = lazyLoanPlan .load ( id , session );
1690
+ final Object selectedValue = values [0 ];
1691
+ initializeLazyProperty (
1692
+ entity ,
1693
+ entry ,
1694
+ selectedValue ,
1695
+ propertyIndex ,
1696
+ getPropertyTypes ()[propertyIndex ]
1697
+ );
1698
+ return selectedValue ;
1699
+ }
1700
+ catch (JDBCException ex ) {
1701
+ throw session .getJdbcServices ().getSqlExceptionHelper ().convert (
1702
+ ex .getSQLException (),
1703
+ "could not initialize lazy properties: " + infoString ( this , id , getFactory () ),
1704
+ lazyLoanPlan .getJdbcSelect ().getSqlString ()
1705
+ );
1706
+ }
1661
1707
}
1708
+ else {
1709
+ if ( !hasLazyProperties () ) {
1710
+ throw new AssertionFailure ( "no lazy properties" );
1711
+ }
1662
1712
1663
- final PersistentAttributeInterceptor interceptor = asPersistentAttributeInterceptable ( entity ).$$_hibernate_getInterceptor ();
1664
- assert interceptor != null : "Expecting bytecode interceptor to be non-null" ;
1713
+ final PersistentAttributeInterceptor interceptor = asPersistentAttributeInterceptable ( entity ).$$_hibernate_getInterceptor ();
1714
+ assert interceptor != null : "Expecting bytecode interceptor to be non-null" ;
1665
1715
1666
- LOG .tracef ( "Initializing lazy properties from datastore (triggered for `%s`)" , fieldName );
1716
+ LOG .tracef ( "Initializing lazy properties from datastore (triggered for `%s`)" , fieldName );
1667
1717
1668
- final String fetchGroup = getEntityMetamodel ().getBytecodeEnhancementMetadata ()
1669
- .getLazyAttributesMetadata ()
1670
- .getFetchGroupName ( fieldName );
1671
- final List <LazyAttributeDescriptor > fetchGroupAttributeDescriptors = getEntityMetamodel ().getBytecodeEnhancementMetadata ()
1672
- .getLazyAttributesMetadata ()
1673
- .getFetchGroupAttributeDescriptors ( fetchGroup );
1718
+ final String fetchGroup = getEntityMetamodel ().getBytecodeEnhancementMetadata ()
1719
+ .getLazyAttributesMetadata ()
1720
+ .getFetchGroupName ( fieldName );
1721
+ final List <LazyAttributeDescriptor > fetchGroupAttributeDescriptors = getEntityMetamodel ().getBytecodeEnhancementMetadata ()
1722
+ .getLazyAttributesMetadata ()
1723
+ .getFetchGroupAttributeDescriptors ( fetchGroup );
1674
1724
1675
- final Set <String > initializedLazyAttributeNames = interceptor .getInitializedLazyAttributeNames ();
1725
+ final Set <String > initializedLazyAttributeNames = interceptor .getInitializedLazyAttributeNames ();
1676
1726
1677
- final SingleIdArrayLoadPlan lazySelect = getSQLLazySelectLoadPlan ( fetchGroup );
1727
+ final SingleIdArrayLoadPlan lazySelect = getSQLLazySelectLoadPlan ( fetchGroup );
1678
1728
1679
- try {
1680
- Object result = null ;
1681
- final Object [] values = lazySelect .load ( id , session );
1682
- int i = 0 ;
1683
- for ( LazyAttributeDescriptor fetchGroupAttributeDescriptor : fetchGroupAttributeDescriptors ) {
1684
- final boolean previousInitialized = initializedLazyAttributeNames .contains ( fetchGroupAttributeDescriptor .getName () );
1685
-
1686
- if ( previousInitialized ) {
1687
- // todo : one thing we should consider here is potentially un-marking an attribute as dirty based on the selected value
1688
- // we know the current value - getPropertyValue( entity, fetchGroupAttributeDescriptor.getAttributeIndex() );
1689
- // we know the selected value (see selectedValue below)
1690
- // we can use the attribute Type to tell us if they are the same
1691
- //
1692
- // assuming entity is a SelfDirtinessTracker we can also know if the attribute is
1693
- // currently considered dirty, and if really not dirty we would do the un-marking
1694
- //
1695
- // of course that would mean a new method on SelfDirtinessTracker to allow un-marking
1696
-
1697
- // its already been initialized (e.g. by a write) so we don't want to overwrite
1698
- i ++;
1699
- continue ;
1700
- }
1729
+ try {
1730
+ Object result = null ;
1731
+ final Object [] values = lazySelect .load ( id , session );
1732
+ int i = 0 ;
1733
+ for ( LazyAttributeDescriptor fetchGroupAttributeDescriptor : fetchGroupAttributeDescriptors ) {
1734
+ final boolean previousInitialized = initializedLazyAttributeNames .contains (
1735
+ fetchGroupAttributeDescriptor .getName () );
1736
+
1737
+ if ( previousInitialized ) {
1738
+ // todo : one thing we should consider here is potentially un-marking an attribute as dirty based on the selected value
1739
+ // we know the current value - getPropertyValue( entity, fetchGroupAttributeDescriptor.getAttributeIndex() );
1740
+ // we know the selected value (see selectedValue below)
1741
+ // we can use the attribute Type to tell us if they are the same
1742
+ //
1743
+ // assuming entity is a SelfDirtinessTracker we can also know if the attribute is
1744
+ // currently considered dirty, and if really not dirty we would do the un-marking
1745
+ //
1746
+ // of course that would mean a new method on SelfDirtinessTracker to allow un-marking
1747
+
1748
+ // its already been initialized (e.g. by a write) so we don't want to overwrite
1749
+ i ++;
1750
+ continue ;
1751
+ }
1701
1752
1702
- final Object selectedValue = values [i ++];
1703
- final boolean set = initializeLazyProperty (
1704
- fieldName ,
1705
- entity ,
1706
- entry ,
1707
- fetchGroupAttributeDescriptor .getLazyIndex (),
1708
- selectedValue
1709
- );
1710
- if ( set ) {
1711
- result = selectedValue ;
1712
- interceptor .attributeInitialized ( fetchGroupAttributeDescriptor .getName () );
1753
+ final Object selectedValue = values [i ++];
1754
+ final boolean set = initializeLazyProperty (
1755
+ fieldName ,
1756
+ entity ,
1757
+ entry ,
1758
+ fetchGroupAttributeDescriptor ,
1759
+ selectedValue
1760
+ );
1761
+ if ( set ) {
1762
+ result = selectedValue ;
1763
+ interceptor .attributeInitialized ( fetchGroupAttributeDescriptor .getName () );
1764
+ }
1713
1765
}
1714
1766
1715
- }
1767
+ LOG . trace ( "Done initializing lazy properties" );
1716
1768
1717
- LOG . trace ( "Done initializing lazy properties" ) ;
1769
+ return result ;
1718
1770
1719
- return result ;
1720
- }
1721
- catch ( JDBCException ex ) {
1722
- throw session . getJdbcServices (). getSqlExceptionHelper (). convert (
1723
- ex . getSQLException ( ),
1724
- "could not initialize lazy properties: " + infoString ( this , id , getFactory () ),
1725
- lazySelect . getJdbcSelect (). getSqlString ()
1726
- );
1771
+ }
1772
+ catch ( JDBCException ex ) {
1773
+ throw session . getJdbcServices (). getSqlExceptionHelper (). convert (
1774
+ ex . getSQLException (),
1775
+ "could not initialize lazy properties: " + infoString ( this , id , getFactory () ),
1776
+ lazySelect . getJdbcSelect (). getSqlString ()
1777
+ );
1778
+ }
1727
1779
}
1728
1780
}
1729
1781
@@ -1782,6 +1834,43 @@ protected boolean initializeLazyProperty(
1782
1834
return fieldName .equals ( lazyPropertyNames [index ] );
1783
1835
}
1784
1836
1837
+
1838
+
1839
+ protected boolean initializeLazyProperty (
1840
+ final String fieldName ,
1841
+ final Object entity ,
1842
+ final EntityEntry entry ,
1843
+ LazyAttributeDescriptor fetchGroupAttributeDescriptor ,
1844
+ final Object propValue ) {
1845
+ final String name = fetchGroupAttributeDescriptor .getName ();
1846
+ initializeLazyProperty (
1847
+ entity ,
1848
+ entry ,
1849
+ propValue ,
1850
+ getPropertyIndex ( name ),
1851
+ fetchGroupAttributeDescriptor .getType ()
1852
+ );
1853
+ return fieldName .equals ( name );
1854
+ }
1855
+
1856
+ private void initializeLazyProperty (Object entity , EntityEntry entry , Object propValue , int index , Type type ) {
1857
+ setPropertyValue ( entity , index , propValue );
1858
+ if ( entry .getLoadedState () != null ) {
1859
+ // object have been loaded with setReadOnly(true); HHH-2236
1860
+ entry .getLoadedState ()[index ] = type .deepCopy (
1861
+ propValue ,
1862
+ factory
1863
+ );
1864
+ }
1865
+ // If the entity has deleted state, then update that as well
1866
+ if ( entry .getDeletedState () != null ) {
1867
+ entry .getDeletedState ()[index ] = type .deepCopy (
1868
+ propValue ,
1869
+ factory
1870
+ );
1871
+ }
1872
+ }
1873
+
1785
1874
@ Override
1786
1875
public NavigableRole getNavigableRole () {
1787
1876
return navigableRole ;
@@ -3227,7 +3316,7 @@ else if ( discriminatorValue == NOT_NULL_DISCRIMINATOR ) {
3227
3316
return new NullnessPredicate ( sqlExpression , true );
3228
3317
}
3229
3318
else if ( hasNull ) {
3230
- junction .add ( new NullnessPredicate ( sqlExpression ) );
3319
+ junction .add ( new NullnessPredicate ( sqlExpression ) );
3231
3320
}
3232
3321
3233
3322
junction .add ( predicate );
0 commit comments