@@ -257,6 +257,7 @@ public abstract class AbstractEntityPersister
257257 private final EntityLoaderLazyCollection loaders = new EntityLoaderLazyCollection ();
258258
259259 private volatile Map <String ,EntityLoader > uniqueKeyLoaders ;
260+ private volatile Map <LockMode ,EntityLoader > naturalIdLoaders ;
260261
261262 // SQL strings
262263 private String sqlVersionSelectString ;
@@ -2478,40 +2479,56 @@ public Object loadByUniqueKey(
24782479 String propertyName ,
24792480 Object uniqueKey ,
24802481 SharedSessionContractImplementor session ) throws HibernateException {
2481- return getAppropriateUniqueKeyLoader ( propertyName , session ).loadByUniqueKey ( session , uniqueKey );
2482+ return getAppropriateUniqueKeyLoader ( propertyName , session )
2483+ .loadByUniqueKey ( session , uniqueKey );
24822484 }
24832485
24842486 public Object loadByNaturalId (
24852487 Object [] naturalIdValues ,
24862488 LockOptions lockOptions ,
24872489 SharedSessionContractImplementor session ) throws HibernateException {
2488- //TODO: cache this
2489- return new EntityLoader (
2490- this ,
2491- determineValueNullness ( naturalIdValues ),
2492- 1 ,
2493- lockOptions ,
2494- getFactory (),
2495- session .getLoadQueryInfluencers ()
2496- ).loadByUniqueKey ( session , naturalIdValues );
2490+ return getAppropriateNaturalIdLoader ( determineValueNullness ( naturalIdValues ), lockOptions , session )
2491+ .loadByUniqueKey ( session , naturalIdValues );
24972492 }
24982493
2499- private EntityLoader getAppropriateUniqueKeyLoader (String propertyName , SharedSessionContractImplementor session ) {
2500- final boolean useStaticLoader = !session .getLoadQueryInfluencers ().hasEnabledFilters ()
2501- && !session .getLoadQueryInfluencers ().hasEnabledFetchProfiles ()
2502- && propertyName .indexOf ( '.' ) < 0 ; //ugly little workaround for fact that createUniqueKeyLoaders() does not handle component properties
2494+ private EntityLoader getAppropriateNaturalIdLoader (
2495+ boolean [] valueNullness ,
2496+ LockOptions lockOptions ,
2497+ SharedSessionContractImplementor session ) {
2498+ LoadQueryInfluencers loadQueryInfluencers = session .getLoadQueryInfluencers ();
2499+ return useStaticNaturalIdLoader ( valueNullness , lockOptions , loadQueryInfluencers )
2500+ ? naturalIdLoaders .get ( lockOptions .getLockMode () ) :
2501+ createNaturalIdLoader ( valueNullness , lockOptions , loadQueryInfluencers );
2502+ }
25032503
2504- if ( useStaticLoader ) {
2505- final Map <String , EntityLoader > uniqueKeyLoaders = this .uniqueKeyLoaders ;
2506- return uniqueKeyLoaders == null ? null : uniqueKeyLoaders .get ( propertyName );
2507- }
2508- else {
2509- return createUniqueKeyLoader (
2510- propertyMapping .toType ( propertyName ),
2511- propertyMapping .toColumns ( propertyName ),
2512- session .getLoadQueryInfluencers ()
2513- );
2514- }
2504+ private boolean useStaticNaturalIdLoader (
2505+ boolean [] valueNullness ,
2506+ LockOptions lockOptions ,
2507+ LoadQueryInfluencers loadQueryInfluencers ) {
2508+ return lockOptions .getTimeOut () == LockOptions .WAIT_FOREVER
2509+ && ArrayHelper .isAllFalse ( valueNullness )
2510+ && !loadQueryInfluencers .hasEnabledFilters ()
2511+ && !loadQueryInfluencers .hasEnabledFetchProfiles ();
2512+ }
2513+
2514+ private EntityLoader getAppropriateUniqueKeyLoader (
2515+ String propertyName ,
2516+ SharedSessionContractImplementor session ) {
2517+ LoadQueryInfluencers loadQueryInfluencers = session .getLoadQueryInfluencers ();
2518+ return useStaticUniqueKeyLoader ( propertyName , loadQueryInfluencers )
2519+ ? uniqueKeyLoaders .get ( propertyName )
2520+ : createUniqueKeyLoader (
2521+ propertyMapping .toType ( propertyName ),
2522+ propertyMapping .toColumns ( propertyName ),
2523+ loadQueryInfluencers
2524+ );
2525+ }
2526+
2527+ private boolean useStaticUniqueKeyLoader (String propertyName , LoadQueryInfluencers loadQueryInfluencers ) {
2528+ return !loadQueryInfluencers .hasEnabledFilters ()
2529+ && !loadQueryInfluencers .hasEnabledFetchProfiles ()
2530+ //ugly little workaround for fact that createUniqueKeyLoaders() does not handle component properties
2531+ && propertyName .indexOf ( '.' ) < 0 ;
25152532 }
25162533
25172534 public int getPropertyIndex (String propertyName ) {
@@ -2521,10 +2538,10 @@ public int getPropertyIndex(String propertyName) {
25212538 protected void createUniqueKeyLoaders () throws MappingException {
25222539 Type [] propertyTypes = getPropertyTypes ();
25232540 String [] propertyNames = getPropertyNames ();
2524- for ( int i = 0 ; i < entityMetamodel . getPropertySpan () ; i ++ ) {
2541+ for ( int i = 0 ; i < propertyUniqueness . length ; i ++ ) {
25252542 if ( propertyUniqueness [i ] ) {
25262543 if ( uniqueKeyLoaders == null ) {
2527- this . uniqueKeyLoaders = new HashMap <>();
2544+ uniqueKeyLoaders = new HashMap <>();
25282545 }
25292546 //don't need filters for the static loaders
25302547 uniqueKeyLoaders .put (
@@ -2538,6 +2555,9 @@ protected void createUniqueKeyLoaders() throws MappingException {
25382555 //TODO: create uk loaders for component properties
25392556 }
25402557 }
2558+ if ( uniqueKeyLoaders == null ) {
2559+ uniqueKeyLoaders = Collections .emptyMap ();
2560+ }
25412561 }
25422562
25432563 private EntityLoader createUniqueKeyLoader (
@@ -2559,6 +2579,40 @@ private EntityLoader createUniqueKeyLoader(
25592579 );
25602580 }
25612581
2582+ protected void createNaturalIdLoaders () throws MappingException {
2583+ if ( hasNaturalIdentifier () ) {
2584+ naturalIdLoaders = new HashMap <>();
2585+ boolean [] valueNullness = new boolean [ getNaturalIdentifierProperties ().length ];
2586+ for ( LockMode lockMode : LockMode .values () ) {
2587+ naturalIdLoaders .put (
2588+ lockMode ,
2589+ createNaturalIdLoader (
2590+ valueNullness ,
2591+ new LockOptions (lockMode ),
2592+ LoadQueryInfluencers .NONE
2593+ )
2594+ );
2595+ }
2596+ }
2597+ else {
2598+ naturalIdLoaders = Collections .emptyMap ();
2599+ }
2600+ }
2601+
2602+ private EntityLoader createNaturalIdLoader (
2603+ boolean [] valueNullness ,
2604+ LockOptions lockOptions ,
2605+ LoadQueryInfluencers loadQueryInfluencers ) {
2606+ return new EntityLoader (
2607+ this ,
2608+ valueNullness ,
2609+ 1 ,
2610+ lockOptions ,
2611+ getFactory (),
2612+ loadQueryInfluencers
2613+ );
2614+ }
2615+
25622616 protected String getSQLWhereString (String alias ) {
25632617 return StringHelper .replace ( sqlWhereStringTemplate , Template .TEMPLATE , alias );
25642618 }
@@ -4356,6 +4410,7 @@ public final void postInstantiate() throws MappingException {
43564410
43574411 createLoaders ();
43584412 createUniqueKeyLoaders ();
4413+ createNaturalIdLoaders ();
43594414 createQueryLoader ();
43604415
43614416 doPostInstantiate ();
@@ -4570,33 +4625,32 @@ protected UniqueEntityLoader getAppropriateLoader(LockOptions lockOptions, Share
45704625 // regardless of any other consideration
45714626 return queryLoader ;
45724627 }
4573- else if ( isAffectedByEnabledFilters ( session ) ) {
4574- // because filters affect the rows returned (because they add
4575- // restrictions) these need to be next in precedence
4576- return createEntityLoader ( lockOptions , session .getLoadQueryInfluencers () );
4577- }
4578- else if ( session .getLoadQueryInfluencers ().getInternalFetchProfile () != null && LockMode .UPGRADE .greaterThan (
4579- lockOptions .getLockMode ()
4580- ) ) {
4581- // Next, we consider whether an 'internal' fetch profile has been set.
4582- // This indicates a special fetch profile Hibernate needs applied
4583- // (for its merge loading process e.g.).
4584- final String internalFetchProfile = session .getLoadQueryInfluencers ().getInternalFetchProfile ();
4585- return getLoaderByString ( internalFetchProfile );
4586- }
4587- else if ( isAffectedByEnabledFetchProfiles ( session ) ) {
4588- // If the session has associated influencers we need to adjust the
4589- // SQL query used for loading based on those influencers
4590- return createEntityLoader ( lockOptions , session .getLoadQueryInfluencers () );
4591- }
4592- else if ( isAffectedByEntityGraph ( session ) ) {
4593- return createEntityLoader ( lockOptions , session .getLoadQueryInfluencers () );
4594- }
4595- else if ( lockOptions .getTimeOut () != LockOptions .WAIT_FOREVER ) {
4596- return createEntityLoader ( lockOptions , session .getLoadQueryInfluencers () );
4597- }
45984628 else {
4599- return getLoaderByLockMode ( lockOptions .getLockMode () );
4629+ LoadQueryInfluencers loadQueryInfluencers = session .getLoadQueryInfluencers ();
4630+ if ( isAffectedByEnabledFilters ( session ) ) {
4631+ // because filters affect the rows returned (because they add
4632+ // restrictions) these need to be next in precedence
4633+ return createEntityLoader ( lockOptions , loadQueryInfluencers );
4634+ }
4635+ else if ( loadQueryInfluencers .getInternalFetchProfile () != null
4636+ && LockMode .UPGRADE .greaterThan ( lockOptions .getLockMode () ) ) {
4637+ // Next, we consider whether an 'internal' fetch profile has been set.
4638+ // This indicates a special fetch profile Hibernate needs applied
4639+ // (for its merge loading process e.g.).
4640+ return getLoaderByString ( loadQueryInfluencers .getInternalFetchProfile () );
4641+ }
4642+ else if ( isAffectedByEnabledFetchProfiles ( session )
4643+ || isAffectedByEntityGraph ( session ) ) {
4644+ // If the session has associated influencers we need to adjust the
4645+ // SQL query used for loading based on those influencers
4646+ return createEntityLoader ( lockOptions , loadQueryInfluencers );
4647+ }
4648+ else if ( lockOptions .getTimeOut () != LockOptions .WAIT_FOREVER ) {
4649+ return createEntityLoader ( lockOptions , loadQueryInfluencers );
4650+ }
4651+ else {
4652+ return getLoaderByLockMode ( lockOptions .getLockMode () );
4653+ }
46004654 }
46014655 }
46024656
0 commit comments