|
13 | 13 | import org.hibernate.loader.ast.spi.MultiNaturalIdLoadOptions; |
14 | 14 | import org.hibernate.loader.ast.spi.MultiNaturalIdLoader; |
15 | 15 | import org.hibernate.metamodel.mapping.EntityMappingType; |
| 16 | +import org.hibernate.metamodel.mapping.NaturalIdMapping; |
16 | 17 |
|
17 | | -import java.util.Collections; |
18 | 18 | import java.util.List; |
19 | 19 |
|
| 20 | +import static java.util.Collections.emptyList; |
20 | 21 | import static org.hibernate.internal.util.collections.CollectionHelper.arrayList; |
21 | 22 | import static org.hibernate.internal.util.collections.CollectionHelper.isEmpty; |
22 | 23 | import static org.hibernate.loader.ast.internal.LoaderHelper.upgradeLock; |
| 24 | +import static org.hibernate.loader.ast.internal.MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER; |
23 | 25 |
|
24 | 26 | /** |
25 | 27 | * @author Jan Schatteman |
26 | 28 | */ |
27 | 29 | public abstract class AbstractMultiNaturalIdLoader<E> implements MultiNaturalIdLoader<E> { |
28 | 30 | private final EntityMappingType entityDescriptor; |
29 | 31 |
|
30 | | - protected MultiNaturalIdLoadOptions options; |
31 | | - |
32 | 32 | public AbstractMultiNaturalIdLoader(EntityMappingType entityDescriptor) { |
33 | 33 | this.entityDescriptor = entityDescriptor; |
34 | 34 | } |
35 | 35 |
|
36 | 36 | @Override |
37 | 37 | public <K> List<E> multiLoad(K[] naturalIds, MultiNaturalIdLoadOptions options, SharedSessionContractImplementor session) { |
38 | 38 | assert naturalIds != null; |
39 | | - |
40 | | - this.options = options; |
41 | | - |
42 | 39 | if ( naturalIds.length == 0 ) { |
43 | | - return Collections.emptyList(); |
| 40 | + return emptyList(); |
| 41 | + } |
| 42 | + else { |
| 43 | + return options.isOrderReturnEnabled() |
| 44 | + ? performOrderedMultiLoad( naturalIds, options, session ) |
| 45 | + : performUnorderedMultiLoad( naturalIds, options, session ); |
44 | 46 | } |
45 | | - |
46 | | - return options.isOrderReturnEnabled() |
47 | | - ? performOrderedMultiLoad( naturalIds, options, session ) |
48 | | - : performUnorderedMultiLoad( naturalIds, options, session ); |
49 | 47 | } |
50 | 48 |
|
51 | | - private <K> List<E> performUnorderedMultiLoad(K[] naturalIds, MultiNaturalIdLoadOptions options, SharedSessionContractImplementor session) { |
52 | | - if ( MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER.isTraceEnabled() ) { |
53 | | - MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER.tracef( "Unordered MultiLoad Starting - `%s`", getEntityDescriptor().getEntityName() ); |
| 49 | + private <K> List<E> performUnorderedMultiLoad( |
| 50 | + K[] naturalIds, |
| 51 | + MultiNaturalIdLoadOptions loadOptions, |
| 52 | + SharedSessionContractImplementor session) { |
| 53 | + if ( MULTI_KEY_LOAD_LOGGER.isTraceEnabled() ) { |
| 54 | + MULTI_KEY_LOAD_LOGGER.tracef( "Unordered MultiLoad starting: " |
| 55 | + + getEntityDescriptor().getEntityName() ); |
54 | 56 | } |
| 57 | + return unorderedMultiLoad( naturalIds, loadOptions, session ); |
| 58 | + } |
55 | 59 |
|
56 | | - return unorderedMultiLoad( |
57 | | - naturalIds, |
58 | | - session, |
59 | | - options.getLockOptions() == null ? LockOptions.NONE : options.getLockOptions() |
60 | | - ); |
| 60 | + private static LockOptions lockOptions(MultiNaturalIdLoadOptions loadOptions) { |
| 61 | + final LockOptions lockOptions = loadOptions.getLockOptions(); |
| 62 | + return lockOptions == null ? LockOptions.NONE : lockOptions; |
61 | 63 | } |
62 | 64 |
|
63 | | - protected <K> List<E> unorderedMultiLoad(K[] naturalIds, SharedSessionContractImplementor session, LockOptions lockOptions) { |
| 65 | + private <K> List<E> unorderedMultiLoad( |
| 66 | + K[] naturalIds, |
| 67 | + MultiNaturalIdLoadOptions loadOptions, |
| 68 | + SharedSessionContractImplementor session) { |
64 | 69 | final List<E> results = arrayList( naturalIds.length ); |
| 70 | + final LockOptions lockOptions = lockOptions( loadOptions ); |
65 | 71 | final Object[] unresolvedIds = |
66 | | - checkPersistenceContextForCachedResults( naturalIds, session, lockOptions, results ); |
| 72 | + checkPersistenceContextForCachedResults( naturalIds, loadOptions, session, lockOptions, results ); |
67 | 73 | if ( !isEmpty( unresolvedIds ) ) { |
68 | | - results.addAll( loadEntitiesWithUnresolvedIds(unresolvedIds, session, lockOptions) ); |
| 74 | + results.addAll( loadEntitiesWithUnresolvedIds( unresolvedIds, loadOptions, lockOptions, session ) ); |
69 | 75 | } |
70 | | - |
71 | 76 | return results; |
72 | 77 | } |
73 | 78 |
|
74 | | - protected abstract List<E> loadEntitiesWithUnresolvedIds(Object[] unresolvedIds, SharedSessionContractImplementor session, LockOptions lockOptions); |
| 79 | + protected abstract List<E> loadEntitiesWithUnresolvedIds( |
| 80 | + Object[] unresolvedIds, |
| 81 | + MultiNaturalIdLoadOptions loadOptions, |
| 82 | + LockOptions lockOptions, |
| 83 | + SharedSessionContractImplementor session); |
75 | 84 |
|
76 | 85 | private <K> List<E> performOrderedMultiLoad(K[] naturalIds, MultiNaturalIdLoadOptions options, SharedSessionContractImplementor session) { |
77 | | - if ( MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER.isTraceEnabled() ) { |
78 | | - MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER.tracef( "Ordered MultiLoad Starting - `%s`", getEntityDescriptor().getEntityName() ); |
| 86 | + if ( MULTI_KEY_LOAD_LOGGER.isTraceEnabled() ) { |
| 87 | + MULTI_KEY_LOAD_LOGGER.trace( "Ordered MultiLoad starting: " |
| 88 | + + getEntityDescriptor().getEntityName() ); |
79 | 89 | } |
80 | | - |
81 | | - return orderedMultiLoad( |
82 | | - naturalIds, |
83 | | - session, |
84 | | - options.getLockOptions() == null ? LockOptions.NONE : options.getLockOptions() |
85 | | - ); |
| 90 | + return orderedMultiLoad( naturalIds, options, session ); |
86 | 91 | } |
87 | 92 |
|
88 | | - protected <K> List<E> orderedMultiLoad( K[] naturalIds, SharedSessionContractImplementor session, LockOptions lockOptions ) { |
89 | | - |
90 | | - unorderedMultiLoad( naturalIds, session, lockOptions ); |
91 | | - |
92 | | - return sortResults( naturalIds, session, lockOptions ); |
| 93 | + private <K> List<E> orderedMultiLoad( |
| 94 | + K[] naturalIds, |
| 95 | + MultiNaturalIdLoadOptions loadOptions, |
| 96 | + SharedSessionContractImplementor session) { |
| 97 | + unorderedMultiLoad( naturalIds, loadOptions, session ); |
| 98 | + return sortResults( naturalIds, loadOptions, session ); |
93 | 99 | } |
94 | 100 |
|
95 | | - protected <K> List<E> sortResults( K[] naturalIds, SharedSessionContractImplementor session, LockOptions lockOptions ) { |
96 | | - List<E> results = arrayList(naturalIds.length); |
97 | | - for ( int i = 0; i < naturalIds.length; i++ ) { |
98 | | - final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); |
99 | | - |
100 | | - Object id = persistenceContext.getNaturalIdResolutions().findCachedIdByNaturalId( naturalIds[i], getEntityDescriptor() ); |
101 | | - |
102 | | - // Id can be null if a non-existent natural id is requested |
103 | | - Object entity = (id == null) ? null : persistenceContext.getEntity( new EntityKey( id, getEntityDescriptor().getEntityPersister() ) ); |
104 | | - if ( entity != null && !options.isReturnOfDeletedEntitiesEnabled() ) { |
105 | | - // make sure it is not DELETED |
106 | | - final EntityEntry entry = persistenceContext.getEntry( entity ); |
107 | | - if ( entry.getStatus().isDeletedOrGone() ) { |
108 | | - // the entity is locally deleted, and the options ask that we not return such entities... |
109 | | - entity = null; |
110 | | - } |
111 | | - else { |
112 | | - entity = persistenceContext.proxyFor( entity ); |
113 | | - } |
| 101 | + private <K> List<E> sortResults( |
| 102 | + K[] naturalIds, |
| 103 | + MultiNaturalIdLoadOptions loadOptions, |
| 104 | + SharedSessionContractImplementor session) { |
| 105 | + final PersistenceContext context = session.getPersistenceContextInternal(); |
| 106 | + final List<E> results = arrayList( naturalIds.length ); |
| 107 | + for ( K naturalId : naturalIds ) { |
| 108 | + final Object entity = entityForNaturalId( context, naturalId ); |
| 109 | + final Object result; |
| 110 | + if ( entity == null |
| 111 | + // the entity is locally deleted, and the options ask that we not return such entities |
| 112 | + || !loadOptions.isReturnOfDeletedEntitiesEnabled() |
| 113 | + && context.getEntry( entity ).getStatus().isDeletedOrGone() ) { |
| 114 | + result = null; |
114 | 115 | } |
115 | | - results.add( (E) entity ); |
| 116 | + else { |
| 117 | + result = context.proxyFor( entity ); |
| 118 | + } |
| 119 | + results.add( (E) result ); |
116 | 120 | } |
117 | | - |
118 | 121 | return results; |
119 | 122 | } |
120 | 123 |
|
121 | | - private <K> Object[] checkPersistenceContextForCachedResults( K[] naturalIds, SharedSessionContractImplementor session, LockOptions lockOptions, List<E> results ) { |
122 | | - List<K> unresolvedIds = arrayList(naturalIds.length); |
123 | | - |
124 | | - final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); |
125 | | - for ( int i = 0; i < naturalIds.length; i++ ) { |
126 | | - |
127 | | - final Object normalizedNaturalId = getEntityDescriptor().getNaturalIdMapping().normalizeInput( naturalIds[i] ); |
128 | | - Object id = persistenceContext.getNaturalIdResolutions().findCachedIdByNaturalId( normalizedNaturalId, getEntityDescriptor() ); |
129 | | - |
130 | | - // Id can be null if a non-existent natural id is requested, or a mutable natural id was changed and then deleted |
131 | | - Object entity = id == null ? null : persistenceContext.getEntity( new EntityKey( id, getEntityDescriptor().getEntityPersister() ) ); |
| 124 | + private <K> Object entityForNaturalId(PersistenceContext context, K naturalId) { |
| 125 | + final EntityMappingType descriptor = getEntityDescriptor(); |
| 126 | + final Object id = context.getNaturalIdResolutions().findCachedIdByNaturalId( naturalId, descriptor ); |
| 127 | + // id can be null if a non-existent natural id is requested, or a mutable natural id was changed and then deleted |
| 128 | + return id == null ? null : context.getEntity( new EntityKey( id, descriptor.getEntityPersister() ) ); |
| 129 | + } |
132 | 130 |
|
| 131 | + private <K> Object[] checkPersistenceContextForCachedResults( |
| 132 | + K[] naturalIds, |
| 133 | + MultiNaturalIdLoadOptions loadOptions, |
| 134 | + SharedSessionContractImplementor session, |
| 135 | + LockOptions lockOptions, |
| 136 | + List<E> results ) { |
| 137 | + final List<K> unresolvedIds = arrayList( naturalIds.length ); |
| 138 | + final PersistenceContext context = session.getPersistenceContextInternal(); |
| 139 | + final NaturalIdMapping naturalIdMapping = getEntityDescriptor().getNaturalIdMapping(); |
| 140 | + for ( K naturalId : naturalIds ) { |
| 141 | + final Object entity = entityForNaturalId( context, naturalIdMapping.normalizeInput( naturalId ) ); |
133 | 142 | if ( entity != null ) { |
134 | 143 | // Entity is already in the persistence context |
135 | | - final EntityEntry entry = persistenceContext.getEntry( entity ); |
136 | | - // either a managed entry, or a deleted one with returnDeleted enabled |
137 | | - if ( !entry.getStatus().isDeletedOrGone() || options.isReturnOfDeletedEntitiesEnabled() ) { |
138 | | - results.add( (E) persistenceContext.proxyFor(entity) ); |
139 | | - upgradeLock( entity, entry, lockOptions, session.getSession().asEventSource() ); |
| 144 | + final EntityEntry entry = context.getEntry( entity ); |
| 145 | + if ( loadOptions.isReturnOfDeletedEntitiesEnabled() |
| 146 | + || !entry.getStatus().isDeletedOrGone() ) { |
| 147 | + // either a managed entry, or a deleted one with returnDeleted enabled |
| 148 | + upgradeLock( entity, entry, lockOptions, session ); |
| 149 | + final Object result = context.proxyFor( entity ); |
| 150 | + results.add( (E) result ); |
140 | 151 | } |
141 | 152 | } |
142 | 153 | else { |
143 | | - // entity either doesn't exist or hasn't been loaded in the PC yet, in both cases we add the natural id |
144 | | - // to the ids that still need to be recovered, in case the id corresponds to a non-existent |
145 | | - // instance nothing will be in the results for it, which is ok in unordered multiload |
146 | | - unresolvedIds.add(naturalIds[i]); |
| 154 | + // entity either doesn't exist or hasn't been loaded in the PC yet, in both cases we add |
| 155 | + // the natural id to the ids that still need to be recovered, in case the id corresponds |
| 156 | + // to a nonexistent instance nothing will be in the results for it, which is ok in |
| 157 | + // unordered multiload |
| 158 | + unresolvedIds.add( naturalId ); |
147 | 159 | } |
148 | 160 | } |
149 | | - |
150 | | - return unresolvedIds.toArray( new Object[0] ); |
| 161 | + return unresolvedIds.toArray(); |
151 | 162 | } |
152 | 163 |
|
153 | 164 | @Override |
|
0 commit comments