Skip to content

Commit c133e0d

Browse files
committed
cleanups and sync with core for cascade stuff
1 parent 9351121 commit c133e0d

File tree

3 files changed

+97
-71
lines changed

3 files changed

+97
-71
lines changed

hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/Cascade.java

Lines changed: 71 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66
package org.hibernate.reactive.engine.impl;
77

88
import java.lang.invoke.MethodHandles;
9+
import java.util.ArrayList;
910
import java.util.Collection;
1011
import java.util.Iterator;
12+
import java.util.List;
1113
import java.util.Objects;
1214
import java.util.concurrent.CompletionStage;
1315

@@ -32,14 +34,15 @@
3234
import org.hibernate.reactive.session.ReactiveSession;
3335
import org.hibernate.type.AssociationType;
3436
import org.hibernate.type.CollectionType;
37+
import org.hibernate.type.ComponentType;
3538
import org.hibernate.type.CompositeType;
3639
import org.hibernate.type.EntityType;
37-
import org.hibernate.type.ForeignKeyDirection;
3840
import org.hibernate.type.Type;
3941

4042
import static org.hibernate.pretty.MessageHelper.infoString;
4143
import static org.hibernate.reactive.util.impl.CompletionStages.loop;
4244
import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture;
45+
import static org.hibernate.type.ForeignKeyDirection.TO_PARENT;
4346

4447
/**
4548
* Delegate responsible for, in conjunction with the various
@@ -90,7 +93,7 @@ public static CompletionStage<?> fetchLazyAssociationsBeforeCascade(
9093
CompletionStage<?> beforeDelete = voidFuture();
9194
if ( persister.hasCascades() ) {
9295
CascadeStyle[] cascadeStyles = persister.getPropertyCascadeStyles();
93-
Object[] state = persister.getPropertyValues( entity );
96+
Object[] state = persister.getValues( entity );
9497
for (int i = 0; i < cascadeStyles.length; i++) {
9598
if ( cascadeStyles[i].doCascade( action.delegate() ) ) {
9699
Object fetchable = state[i];
@@ -105,13 +108,11 @@ public static CompletionStage<?> fetchLazyAssociationsBeforeCascade(
105108

106109
/**
107110
* Cascade an action from the parent entity instance to all its children.
108-
*
109-
* which is specific to each CascadingAction type
110111
*/
111112
public CompletionStage<Void> cascade() throws HibernateException {
112113
return voidFuture().thenCompose(v -> {
113114
CacheMode cacheMode = eventSource.getCacheMode();
114-
if (action==CascadingActions.DELETE) {
115+
if ( action==CascadingActions.DELETE ) {
115116
eventSource.setCacheMode( CacheMode.GET );
116117
}
117118
eventSource.getPersistenceContextInternal().incrementCascadeLevel();
@@ -135,14 +136,14 @@ private CompletionStage<Void> cascadeInternal() throws HibernateException {
135136
final String[] propertyNames = persister.getPropertyNames();
136137
final CascadeStyle[] cascadeStyles = persister.getPropertyCascadeStyles();
137138
final boolean hasUninitializedLazyProperties = persister.hasUninitializedLazyProperties( parent );
138-
final int componentPathStackDepth = 0;
139139
for ( int i = 0; i < types.length; i++) {
140140
final CascadeStyle style = cascadeStyles[ i ];
141141
final String propertyName = propertyNames[ i ];
142142
final boolean isUninitializedProperty =
143143
hasUninitializedLazyProperties &&
144144
!persister.getBytecodeEnhancementMetadata().isAttributeLoaded( parent, propertyName );
145145

146+
final Type type = types[i];
146147
if ( style.doCascade( action.delegate() ) ) {
147148
final Object child;
148149
if ( isUninitializedProperty ) {
@@ -156,28 +157,28 @@ private CompletionStage<Void> cascadeInternal() throws HibernateException {
156157
// parent was not in the PersistenceContext
157158
continue;
158159
}
159-
if ( types[ i ].isCollectionType() ) {
160+
if ( type.isCollectionType() ) {
160161
// CollectionType#getCollection gets the PersistentCollection
161162
// that corresponds to the uninitialized collection from the
162163
// PersistenceContext. If not present, an uninitialized
163164
// PersistentCollection will be added to the PersistenceContext.
164165
// The action may initialize it later, if necessary.
165166
// This needs to be done even when action.performOnLazyProperty() returns false.
166-
final CollectionType collectionType = (CollectionType) types[i];
167+
final CollectionType collectionType = (CollectionType) type;
167168
child = collectionType.getCollection(
168169
collectionType.getKeyOfOwner( parent, eventSource ),
169170
eventSource,
170171
parent,
171172
null
172173
);
173174
}
174-
else if ( types[ i ].isComponentType() ) {
175+
else if ( type.isComponentType() ) {
175176
// Hibernate does not support lazy embeddables, so this shouldn't happen.
176177
throw new UnsupportedOperationException(
177178
"Lazy components are not supported."
178179
);
179180
}
180-
else if ( action.performOnLazyProperty() && types[ i ].isEntityType() ) {
181+
else if ( action.performOnLazyProperty() && type.isEntityType() ) {
181182
// Only need to initialize a lazy entity attribute when action.performOnLazyProperty()
182183
// returns true.
183184
LazyAttributeLoadingInterceptor interceptor = persister.getBytecodeEnhancementMetadata()
@@ -191,12 +192,12 @@ else if ( action.performOnLazyProperty() && types[ i ].isEntityType() ) {
191192
}
192193
}
193194
else {
194-
child = persister.getPropertyValue( parent, i );
195+
child = persister.getValue( parent, i );
195196
}
196197
cascadeProperty(
197-
componentPathStackDepth,
198+
null,
198199
child,
199-
types[ i ],
200+
type,
200201
style,
201202
propertyName,
202203
false
@@ -209,9 +210,9 @@ else if ( action.performOnLazyProperty() && types[ i ].isEntityType() ) {
209210
// If the property is uninitialized, then there cannot be any orphans.
210211
if ( action.deleteOrphans() && !isUninitializedProperty ) {
211212
cascadeLogicalOneToOneOrphanRemoval(
212-
componentPathStackDepth,
213-
persister.getPropertyValue( parent, i ),
214-
types[ i ],
213+
null,
214+
persister.getValue( parent, i ),
215+
type,
215216
style,
216217
propertyName,
217218
false
@@ -241,7 +242,7 @@ private void noCascade(
241242
* Cascade an action to the child or children
242243
*/
243244
private void cascadeProperty(
244-
final int componentPathStackDepth,
245+
List<String> componentPath,
245246
final Object child,
246247
final Type type,
247248
final CascadeStyle style,
@@ -253,7 +254,7 @@ private void cascadeProperty(
253254
final AssociationType associationType = (AssociationType) type;
254255
if ( cascadeAssociationNow( cascadePoint, associationType ) ) {
255256
cascadeAssociation(
256-
componentPathStackDepth,
257+
componentPath,
257258
child,
258259
type,
259260
style,
@@ -262,16 +263,22 @@ private void cascadeProperty(
262263
}
263264
}
264265
else if ( type.isComponentType() ) {
266+
if ( componentPath == null && propertyName != null ) {
267+
componentPath = new ArrayList<>();
268+
}
269+
if ( componentPath != null ) {
270+
componentPath.add( propertyName );
271+
}
265272
cascadeComponent(
266-
componentPathStackDepth,
273+
componentPath,
267274
child,
268275
(CompositeType) type
269276
);
270277
}
271278
}
272279

273280
cascadeLogicalOneToOneOrphanRemoval(
274-
componentPathStackDepth,
281+
componentPath,
275282
child,
276283
type,
277284
style,
@@ -280,7 +287,7 @@ else if ( type.isComponentType() ) {
280287
}
281288

282289
private void cascadeLogicalOneToOneOrphanRemoval(
283-
final int componentPathStackDepth,
290+
final List<String> componentPath,
284291
final Object child,
285292
final Type type,
286293
final CascadeStyle style,
@@ -298,31 +305,38 @@ private void cascadeLogicalOneToOneOrphanRemoval(
298305
final EntityEntry entry = persistenceContext.getEntry( parent );
299306
if ( entry != null && entry.getStatus() != Status.SAVING ) {
300307
Object loadedValue;
301-
if ( componentPathStackDepth == 0 ) {
308+
if ( componentPath == null ) {
302309
// association defined on entity
303310
loadedValue = entry.getLoadedValue( propertyName );
304311
}
305312
else {
306313
// association defined on component
307-
// todo : this is currently unsupported because of the fact that
308-
// we do not know the loaded state of this value properly
309-
// and doing so would be very difficult given how components and
310-
// entities are loaded (and how 'loaded state' is put into the
311-
// EntityEntry). Solutions here are to either:
312-
// 1) properly account for components as a 2-phase load construct
313-
// 2) just assume the association was just now orphaned and
314-
// issue the orphan delete. This would require a special
315-
// set of SQL statements though since we do not know the
316-
// orphaned value, something a delete with a subquery to
317-
// match the owner.
318-
// final EntityType entityType = (EntityType) type;
319-
// final String getPropertyPath = composePropertyPath( entityType.getPropertyName() );
320-
loadedValue = null;
314+
// Since the loadedState in the EntityEntry is a flat domain type array
315+
// We first have to extract the component object and then ask the component type
316+
// recursively to give us the value of the sub-property of that object
317+
final Type propertyType = entry.getPersister().getPropertyType( componentPath.get(0) );
318+
if ( propertyType instanceof ComponentType) {
319+
loadedValue = entry.getLoadedValue( componentPath.get( 0 ) );
320+
ComponentType componentType = (ComponentType) propertyType;
321+
if ( componentPath.size() != 1 ) {
322+
for ( int i = 1; i < componentPath.size(); i++ ) {
323+
final int subPropertyIndex = componentType.getPropertyIndex( componentPath.get( i ) );
324+
loadedValue = componentType.getPropertyValue( loadedValue, subPropertyIndex );
325+
componentType = (ComponentType) componentType.getSubtypes()[subPropertyIndex];
326+
}
327+
}
328+
329+
loadedValue = componentType.getPropertyValue( loadedValue, componentType.getPropertyIndex( propertyName ) );
330+
}
331+
else {
332+
// Association is probably defined in an element collection, so we can't do orphan removals
333+
loadedValue = null;
334+
}
321335
}
322336

323337
// orphaned if the association was nulled (child == null) or receives a new value while the
324338
// entity is managed (without first nulling and manually flushing).
325-
if ( child == null || ( loadedValue != null && child != loadedValue ) ) {
339+
if ( child == null || loadedValue != null && child != loadedValue ) {
326340
EntityEntry valueEntry = persistenceContext.getEntry( loadedValue );
327341

328342
if ( valueEntry == null && loadedValue instanceof HibernateProxy ) {
@@ -342,8 +356,8 @@ private void cascadeLogicalOneToOneOrphanRemoval(
342356
}
343357

344358
if ( valueEntry != null ) {
345-
EntityPersister persister = valueEntry.getPersister();
346-
String entityName = persister.getEntityName();
359+
final EntityPersister persister = valueEntry.getPersister();
360+
final String entityName = persister.getEntityName();
347361
if ( LOG.isTraceEnabled() ) {
348362
LOG.tracev(
349363
"Deleting orphaned entity instance: {0}",
@@ -353,8 +367,7 @@ private void cascadeLogicalOneToOneOrphanRemoval(
353367

354368
final Object loaded = loadedValue;
355369
if ( type.isAssociationType()
356-
&& ( (AssociationType) type ).getForeignKeyDirection()
357-
.equals(ForeignKeyDirection.TO_PARENT) ) {
370+
&& ( (AssociationType) type ).getForeignKeyDirection().equals(TO_PARENT) ) {
358371
// If FK direction is to-parent, we must remove the orphan *before* the queued update(s)
359372
// occur. Otherwise, replacing the association on a managed entity, without manually
360373
// nulling and flushing, causes FK constraint violations.
@@ -390,7 +403,7 @@ private boolean cascadeAssociationNow(final CascadePoint cascadePoint, Associat
390403
}
391404

392405
private void cascadeComponent(
393-
final int componentPathStackDepth,
406+
List<String> componentPath,
394407
final Object child,
395408
final CompositeType componentType) {
396409

@@ -400,13 +413,14 @@ private void cascadeComponent(
400413
for ( int i = 0; i < types.length; i++ ) {
401414
final CascadeStyle componentPropertyStyle = componentType.getCascadeStyle( i );
402415
final String subPropertyName = propertyNames[i];
403-
if ( componentPropertyStyle.doCascade( action.delegate() ) ) {
404-
if (children == null) {
416+
if ( componentPropertyStyle.doCascade( action.delegate() )
417+
|| componentPropertyStyle.hasOrphanDelete() && action.deleteOrphans() ) {
418+
if ( children == null ) {
405419
// Get children on demand.
406420
children = componentType.getPropertyValues( child, eventSource );
407421
}
408422
cascadeProperty(
409-
componentPathStackDepth + 1,
423+
componentPath,
410424
children[i],
411425
types[i],
412426
componentPropertyStyle,
@@ -418,7 +432,7 @@ private void cascadeComponent(
418432
}
419433

420434
private void cascadeAssociation(
421-
final int componentPathStackDepth,
435+
List<String> componentPath,
422436
final Object child,
423437
final Type type,
424438
final CascadeStyle style,
@@ -428,7 +442,7 @@ private void cascadeAssociation(
428442
}
429443
else if ( type.isCollectionType() ) {
430444
cascadeCollection(
431-
componentPathStackDepth,
445+
componentPath,
432446
child,
433447
style,
434448
(CollectionType) type
@@ -440,12 +454,13 @@ else if ( type.isCollectionType() ) {
440454
* Cascade an action to a collection
441455
*/
442456
private void cascadeCollection(
443-
final int componentPathStackDepth,
457+
List<String> componentPath,
444458
final Object child,
445459
final CascadeStyle style,
446460
final CollectionType type) {
447461
final CollectionPersister persister =
448-
eventSource.getFactory().getMetamodel().collectionPersister( type.getRole() );
462+
eventSource.getFactory().getMappingMetamodel()
463+
.getCollectionDescriptor( type.getRole() );
449464
final Type elemType = persister.getElementType();
450465

451466
CascadePoint elementsCascadePoint = cascadePoint;
@@ -456,7 +471,7 @@ private void cascadeCollection(
456471
//cascade to current collection elements
457472
if ( elemType.isEntityType() || elemType.isAnyType() || elemType.isComponentType() ) {
458473
cascadeCollectionElements(
459-
componentPathStackDepth,
474+
componentPath,
460475
child,
461476
type,
462477
style,
@@ -492,7 +507,7 @@ private void cascadeToOne(
492507
* Cascade to the collection elements
493508
*/
494509
private void cascadeCollectionElements(
495-
final int componentPathStackDepth,
510+
List<String> componentPath,
496511
final Object child,
497512
final CollectionType collectionType,
498513
final CascadeStyle style,
@@ -510,7 +525,7 @@ private void cascadeCollectionElements(
510525
final Iterator<?> itr = action.getCascadableChildrenIterator( eventSource, collectionType, child );
511526
while ( itr.hasNext() ) {
512527
cascadeProperty(
513-
componentPathStackDepth,
528+
componentPath,
514529
itr.next(),
515530
elemType,
516531
style,
@@ -527,8 +542,9 @@ private void cascadeCollectionElements(
527542
final boolean deleteOrphans = style.hasOrphanDelete()
528543
&& action.deleteOrphans()
529544
&& elemType.isEntityType()
545+
&& child instanceof PersistentCollection
530546
// a newly instantiated collection can't have orphans
531-
&& child instanceof PersistentCollection;
547+
&& ! ( (PersistentCollection<?>) child ).isNewlyInstantiated();
532548

533549
if ( deleteOrphans ) {
534550
final boolean traceEnabled = LOG.isTraceEnabled();
@@ -539,7 +555,7 @@ private void cascadeCollectionElements(
539555
// 1. newly instantiated collections
540556
// 2. arrays (we can't track orphans for detached arrays)
541557
final String entityName = collectionType.getAssociatedEntityName( eventSource.getFactory() );
542-
deleteOrphans( entityName, (PersistentCollection) child );
558+
deleteOrphans( entityName, (PersistentCollection<?>) child );
543559

544560
if ( traceEnabled ) {
545561
LOG.tracev( "Done deleting orphans for collection: {0}", collectionType.getRole() );
@@ -550,7 +566,7 @@ private void cascadeCollectionElements(
550566
/**
551567
* Delete any entities that were removed from the collection
552568
*/
553-
private void deleteOrphans(String entityName, PersistentCollection pc) throws HibernateException {
569+
private void deleteOrphans(String entityName, PersistentCollection<?> pc) throws HibernateException {
554570
//TODO: suck this logic into the collection!
555571
final Collection<?> orphans;
556572
if ( pc.wasInitialized() ) {

hibernate-reactive-core/src/main/java/org/hibernate/reactive/engine/impl/CascadingAction.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,5 +88,5 @@ Iterator<?> getCascadableChildrenIterator(
8888
*/
8989
boolean performOnLazyProperty();
9090

91-
org.hibernate.engine.spi.CascadingAction delegate();
91+
org.hibernate.engine.spi.CascadingAction<C> delegate();
9292
}

0 commit comments

Comments
 (0)