25
25
import org .hibernate .engine .spi .PersistentAttributeInterceptor ;
26
26
import org .hibernate .engine .spi .SelfDirtinessTracker ;
27
27
import org .hibernate .engine .spi .SessionFactoryImplementor ;
28
- import org .hibernate .engine .spi .SessionImplementor ;
29
28
import org .hibernate .event .spi .EntityCopyObserver ;
30
29
import org .hibernate .event .spi .EventSource ;
31
30
import org .hibernate .event .spi .MergeContext ;
@@ -274,7 +273,7 @@ protected void entityIsPersistent(MergeEvent event, MergeContext copyCache) {
274
273
final EntityPersister persister = source .getEntityPersister ( event .getEntityName (), entity );
275
274
copyCache .put ( entity , entity , true ); //before cascade!
276
275
cascadeOnMerge ( source , persister , entity , copyCache );
277
- copyValues ( persister , entity , entity , source , copyCache );
276
+ TypeHelper . replace ( persister , entity , source , entity , copyCache );
278
277
event .setResult ( entity );
279
278
}
280
279
@@ -285,24 +284,52 @@ protected void entityIsTransient(MergeEvent event, Object id, MergeContext copyC
285
284
final EventSource session = event .getSession ();
286
285
final String entityName = event .getEntityName ();
287
286
final EntityPersister persister = session .getEntityPersister ( entityName , entity );
287
+ final String [] propertyNames = persister .getPropertyNames ();
288
+ final Type [] propertyTypes = persister .getPropertyTypes ();
288
289
final Object copy = copyEntity ( copyCache , entity , session , persister , id );
289
290
290
291
// cascade first, so that all unsaved objects get their
291
292
// copy created before we actually copy
292
293
//cascadeOnMerge(event, persister, entity, copyCache, Cascades.CASCADE_BEFORE_MERGE);
293
294
super .cascadeBeforeSave ( session , persister , entity , copyCache );
294
- copyValues ( persister , entity , copy , session , copyCache , ForeignKeyDirection .FROM_PARENT );
295
+
296
+ final Object [] sourceValues = persister .getValues ( entity );
297
+ session .getInterceptor ().preMerge ( entity , sourceValues , propertyNames , propertyTypes );
298
+ final Object [] copiedValues = TypeHelper .replace (
299
+ sourceValues ,
300
+ persister .getValues ( copy ),
301
+ propertyTypes ,
302
+ session ,
303
+ copy ,
304
+ copyCache ,
305
+ ForeignKeyDirection .FROM_PARENT
306
+ );
307
+ persister .setValues ( copy , copiedValues );
295
308
296
309
saveTransientEntity ( copy , entityName , event .getRequestedId (), session , copyCache );
297
310
298
311
// cascade first, so that all unsaved objects get their
299
312
// copy created before we actually copy
300
313
super .cascadeAfterSave ( session , persister , entity , copyCache );
301
314
302
- copyValues ( persister , entity , copy , session , copyCache , ForeignKeyDirection .TO_PARENT );
315
+ // this is the second pass through on a merge op, so here we limit the
316
+ // replacement to association types (value types were already replaced
317
+ // during the first pass)
318
+ // final Object[] newSourceValues = persister.getValues( entity );
319
+ final Object [] targetValues = TypeHelper .replaceAssociations (
320
+ sourceValues , // newSourceValues,
321
+ persister .getValues ( copy ),
322
+ propertyTypes ,
323
+ session ,
324
+ copy ,
325
+ copyCache ,
326
+ ForeignKeyDirection .TO_PARENT
327
+ );
328
+ persister .setValues ( copy , targetValues );
329
+ session .getInterceptor ().postMerge ( entity , copy , targetValues , null , propertyNames , propertyTypes );
303
330
304
331
// saveTransientEntity has been called using a copy that contains empty collections
305
- // (copyValues uses ` ForeignKeyDirection.FROM_PARENT` ) then the PC may contain a wrong
332
+ // (copyValues uses ForeignKeyDirection.FROM_PARENT) then the PC may contain a wrong
306
333
// collection snapshot, the CollectionVisitor realigns the collection snapshot values
307
334
// with the final copy
308
335
new CollectionVisitor ( copy , id , session )
@@ -382,29 +409,29 @@ protected void entityIsDetached(MergeEvent event, Object copiedId, Object origin
382
409
LOG .trace ( "Merging detached instance" );
383
410
384
411
final Object entity = event .getEntity ();
385
- final EventSource source = event .getSession ();
386
- final EntityPersister persister = source .getEntityPersister ( event .getEntityName (), entity );
412
+ final EventSource session = event .getSession ();
413
+ final EntityPersister persister = session .getEntityPersister ( event .getEntityName (), entity );
387
414
final String entityName = persister .getEntityName ();
388
415
if ( originalId == null ) {
389
- originalId = persister .getIdentifier ( entity , source );
416
+ originalId = persister .getIdentifier ( entity , session );
390
417
}
391
418
final Object clonedIdentifier = copiedId == null
392
419
? persister .getIdentifierType ().deepCopy ( originalId , event .getFactory () )
393
420
: copiedId ;
394
421
final Object id = getDetachedEntityId ( event , originalId , persister );
395
422
// we must clone embedded composite identifiers, or we will get back the same instance that we pass in
396
423
// apply the special MERGE fetch profile and perform the resolution (Session#get)
397
- final Object result = source .getLoadQueryInfluencers ().fromInternalFetchProfile (
424
+ final Object result = session .getLoadQueryInfluencers ().fromInternalFetchProfile (
398
425
CascadingFetchProfile .MERGE ,
399
- () -> source .get ( entityName , clonedIdentifier )
426
+ () -> session .get ( entityName , clonedIdentifier )
400
427
);
401
428
402
429
if ( result == null ) {
403
430
LOG .trace ( "Detached instance not found in database" );
404
431
// we got here because we assumed that an instance
405
432
// with an assigned id and no version was detached,
406
433
// when it was really transient (or deleted)
407
- final Boolean knownTransient = persister .isTransient ( entity , source );
434
+ final Boolean knownTransient = persister .isTransient ( entity , session );
408
435
if ( knownTransient == Boolean .FALSE ) {
409
436
// we know for sure it's detached (generated id
410
437
// or a version property), and so the instance
@@ -424,8 +451,24 @@ protected void entityIsDetached(MergeEvent event, Object copiedId, Object origin
424
451
final Object target = targetEntity ( event , entity , persister , id , result );
425
452
// cascade first, so that all unsaved objects get their
426
453
// copy created before we actually copy
427
- cascadeOnMerge ( source , persister , entity , copyCache );
428
- copyValues ( persister , entity , target , source , copyCache );
454
+ cascadeOnMerge ( session , persister , entity , copyCache );
455
+
456
+ final String [] propertyNames = persister .getPropertyNames ();
457
+ final Type [] propertyTypes = persister .getPropertyTypes ();
458
+
459
+ final Object [] sourceValues = persister .getValues ( entity );
460
+ final Object [] originalValues = persister .getValues ( target );
461
+ session .getInterceptor ().preMerge ( entity , sourceValues , propertyNames , propertyTypes );
462
+ final Object [] targetValues = TypeHelper .replace (
463
+ sourceValues ,
464
+ originalValues ,
465
+ propertyTypes ,
466
+ session ,
467
+ target ,
468
+ copyCache
469
+ );
470
+ persister .setValues ( target , targetValues );
471
+ session .getInterceptor ().postMerge ( entity , target , targetValues , originalValues , propertyNames , propertyTypes );
429
472
//copyValues works by reflection, so explicitly mark the entity instance dirty
430
473
markInterceptorDirty ( entity , target );
431
474
event .setResult ( result );
@@ -570,64 +613,6 @@ private static boolean existsInDatabase(Object entity, EventSource source, Entit
570
613
return entry != null && entry .isExistsInDatabase ();
571
614
}
572
615
573
- protected void copyValues (
574
- final EntityPersister persister ,
575
- final Object entity ,
576
- final Object target ,
577
- final SessionImplementor source ,
578
- final MergeContext copyCache ) {
579
- if ( entity == target ) {
580
- TypeHelper .replace ( persister , entity , source , entity , copyCache );
581
- }
582
- else {
583
- final Object [] copiedValues = TypeHelper .replace (
584
- persister .getValues ( entity ),
585
- persister .getValues ( target ),
586
- persister .getPropertyTypes (),
587
- source ,
588
- target ,
589
- copyCache
590
- );
591
- persister .setValues ( target , copiedValues );
592
- }
593
- }
594
-
595
- protected void copyValues (
596
- final EntityPersister persister ,
597
- final Object entity ,
598
- final Object target ,
599
- final SessionImplementor source ,
600
- final MergeContext copyCache ,
601
- final ForeignKeyDirection foreignKeyDirection ) {
602
- final Object [] copiedValues ;
603
- if ( foreignKeyDirection == ForeignKeyDirection .TO_PARENT ) {
604
- // this is the second pass through on a merge op, so here we limit the
605
- // replacement to associations types (value types were already replaced
606
- // during the first pass)
607
- copiedValues = TypeHelper .replaceAssociations (
608
- persister .getValues ( entity ),
609
- persister .getValues ( target ),
610
- persister .getPropertyTypes (),
611
- source ,
612
- target ,
613
- copyCache ,
614
- foreignKeyDirection
615
- );
616
- }
617
- else {
618
- copiedValues = TypeHelper .replace (
619
- persister .getValues ( entity ),
620
- persister .getValues ( target ),
621
- persister .getPropertyTypes (),
622
- source ,
623
- target ,
624
- copyCache ,
625
- foreignKeyDirection
626
- );
627
- }
628
- persister .setValues ( target , copiedValues );
629
- }
630
-
631
616
/**
632
617
* Perform any cascades needed as part of this copy event.
633
618
*
0 commit comments