Skip to content

Commit 6a7a7ab

Browse files
committed
[#2154] Composite key with generated value not working properly
1 parent 84781fe commit 6a7a7ab

File tree

3 files changed

+158
-10
lines changed

3 files changed

+158
-10
lines changed

hibernate-reactive-core/src/main/java/org/hibernate/reactive/id/ReactiveIdentifierGenerator.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package org.hibernate.reactive.id;
77

88
import org.hibernate.Incubating;
9+
import org.hibernate.generator.EventType;
910
import org.hibernate.generator.Generator;
1011
import org.hibernate.id.IdentifierGenerator;
1112
import org.hibernate.reactive.session.ReactiveConnectionSupplier;
@@ -33,4 +34,8 @@ public interface ReactiveIdentifierGenerator<Id> extends Generator {
3334
* @param session the reactive session
3435
*/
3536
CompletionStage<Id> generate(ReactiveConnectionSupplier session, Object entity);
37+
38+
default CompletionStage<Id> generate(ReactiveConnectionSupplier session, Object owner, Object currentValue, EventType eventType) {
39+
return generate( session, owner );
40+
}
3641
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
/* Hibernate, Relational Persistence for Idiomatic Java
2+
*
3+
* SPDX-License-Identifier: Apache-2.0
4+
* Copyright: Red Hat Inc. and Hibernate Authors
5+
*/
6+
package org.hibernate.reactive.id.impl;
7+
8+
import org.hibernate.engine.spi.SharedSessionContractImplementor;
9+
import org.hibernate.generator.BeforeExecutionGenerator;
10+
import org.hibernate.generator.Generator;
11+
import org.hibernate.generator.GeneratorCreationContext;
12+
import org.hibernate.id.CompositeNestedGeneratedValueGenerator;
13+
import org.hibernate.id.IdentifierGenerationException;
14+
import org.hibernate.mapping.Component;
15+
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
16+
import org.hibernate.reactive.id.ReactiveIdentifierGenerator;
17+
import org.hibernate.reactive.session.ReactiveConnectionSupplier;
18+
import org.hibernate.reactive.tuple.entity.ReactiveEntityMetamodel;
19+
20+
import java.util.ArrayList;
21+
import java.util.List;
22+
import java.util.concurrent.CompletionStage;
23+
24+
import static org.hibernate.generator.EventType.INSERT;
25+
import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture;
26+
import static org.hibernate.reactive.util.impl.CompletionStages.loop;
27+
28+
public class ReactiveCompositeNestedGeneratedValueGenerator extends CompositeNestedGeneratedValueGenerator implements
29+
ReactiveIdentifierGenerator<Object> {
30+
31+
public ReactiveCompositeNestedGeneratedValueGenerator(
32+
CompositeNestedGeneratedValueGenerator generator,
33+
GeneratorCreationContext creationContext,
34+
RuntimeModelCreationContext runtimeModelCreationContext) {
35+
super(
36+
generator.getGenerationContextLocator(),
37+
generator.getCompositeType(),
38+
extracted( generator, creationContext, runtimeModelCreationContext )
39+
);
40+
}
41+
42+
private static List<GenerationPlan> extracted(
43+
CompositeNestedGeneratedValueGenerator generator,
44+
GeneratorCreationContext creationContext,
45+
RuntimeModelCreationContext runtimeModelCreationContext) {
46+
final List<GenerationPlan> plans = new ArrayList<>();
47+
for ( GenerationPlan plan : generator.getGenerationPlans() ) {
48+
final GenerationPlan reactivePlane = new Component.ValueGenerationPlan(
49+
(BeforeExecutionGenerator) ReactiveEntityMetamodel.augmentWithReactiveGenerator(
50+
plan.getGenerator(),
51+
creationContext,
52+
runtimeModelCreationContext
53+
),
54+
plan.getInjector(),
55+
plan.getPropertyIndex()
56+
);
57+
plans.add( reactivePlane );
58+
}
59+
return plans;
60+
}
61+
62+
@Override
63+
public CompletionStage<Object> generate(ReactiveConnectionSupplier reactiveConnectionSupplier, Object object) {
64+
SharedSessionContractImplementor session = (SharedSessionContractImplementor) reactiveConnectionSupplier;
65+
final Object context = getGenerationContextLocator().locateGenerationContext( session, object );
66+
67+
final List<Object> generatedValues = getCompositeType().isMutable()
68+
? null
69+
: new ArrayList<>( getGenerationPlans().size() );
70+
return loop( getGenerationPlans(), generationPlan -> {
71+
final Generator generator = generationPlan.getGenerator();
72+
if ( generator.generatedBeforeExecution( object, session ) ) {
73+
if ( generator instanceof ReactiveIdentifierGenerator<?> reactiveIdentifierGenerator ) {
74+
return reactiveIdentifierGenerator.generate( reactiveConnectionSupplier, object )
75+
.thenAccept( generated -> {
76+
if ( generatedValues != null ) {
77+
generatedValues.add( generated );
78+
}
79+
else {
80+
generationPlan.getInjector().set( context, generated );
81+
}
82+
} );
83+
}
84+
else {
85+
final Object currentValue = generator.allowAssignedIdentifiers()
86+
? getCompositeType().getPropertyValue( context, generationPlan.getPropertyIndex(), session )
87+
: null;
88+
return completedFuture( ( (BeforeExecutionGenerator) generator )
89+
.generate( session, object, currentValue, INSERT ) );
90+
}
91+
}
92+
else {
93+
throw new IdentifierGenerationException( "Identity generation isn't supported for composite ids" );
94+
}
95+
} ).thenCompose( v -> {
96+
if ( generatedValues != null) {
97+
final Object[] values = getCompositeType().getPropertyValues( context );
98+
for ( int i = 0; i < generatedValues.size(); i++ ) {
99+
values[getGenerationPlans().get( i ).getPropertyIndex()] = generatedValues.get( i );
100+
}
101+
return completedFuture( getCompositeType().replacePropertyValues( context, values, session ) );
102+
}
103+
else {
104+
return completedFuture(context);
105+
}
106+
} );
107+
}
108+
}

hibernate-reactive-core/src/main/java/org/hibernate/reactive/tuple/entity/ReactiveEntityMetamodel.java

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
import org.hibernate.generator.Generator;
1212
import org.hibernate.generator.GeneratorCreationContext;
13+
import org.hibernate.id.CompositeNestedGeneratedValueGenerator;
1314
import org.hibernate.id.Configurable;
1415
import org.hibernate.id.IdentifierGenerator;
1516
import org.hibernate.id.SelectGenerator;
@@ -18,13 +19,15 @@
1819
import org.hibernate.id.enhanced.SequenceStyleGenerator;
1920
import org.hibernate.id.enhanced.TableGenerator;
2021
import org.hibernate.id.enhanced.TableStructure;
22+
import org.hibernate.mapping.Component;
2123
import org.hibernate.mapping.GeneratorCreator;
2224
import org.hibernate.mapping.PersistentClass;
2325
import org.hibernate.mapping.SimpleValue;
2426
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
2527
import org.hibernate.persister.entity.EntityPersister;
2628
import org.hibernate.reactive.id.ReactiveIdentifierGenerator;
2729
import org.hibernate.reactive.id.impl.EmulatedSequenceReactiveIdentifierGenerator;
30+
import org.hibernate.reactive.id.impl.ReactiveCompositeNestedGeneratedValueGenerator;
2831
import org.hibernate.reactive.id.impl.ReactiveGeneratorWrapper;
2932
import org.hibernate.reactive.id.impl.ReactiveSequenceIdentifierGenerator;
3033
import org.hibernate.reactive.id.impl.TableReactiveIdentifierGenerator;
@@ -67,12 +70,9 @@ private static Generator buildIdGenerator(
6770
return existing;
6871
}
6972
else {
70-
SimpleValue identifier = (SimpleValue) persistentClass.getIdentifier();
71-
GeneratorCreator customIdGeneratorCreator = identifier.getCustomIdGeneratorCreator();
72-
identifier.setCustomIdGeneratorCreator( context -> {
73-
Generator generator = customIdGeneratorCreator.createGenerator( context );
74-
return augmentWithReactiveGenerator( generator, context, creationContext );
75-
} );
73+
final SimpleValue identifier = (SimpleValue) persistentClass.getIdentifier();
74+
setCustomIdGenerator( persistentClass, creationContext, identifier );
75+
7676
final Generator idgenerator = identifier
7777
// returns the cached Generator if it was already created
7878
.createGenerator(
@@ -86,12 +86,35 @@ private static Generator buildIdGenerator(
8686
}
8787
}
8888

89+
private static void setCustomIdGenerator(
90+
PersistentClass persistentClass,
91+
RuntimeModelCreationContext creationContext,
92+
SimpleValue identifier) {
93+
final GeneratorCreator customIdGeneratorCreator = identifier.getCustomIdGeneratorCreator();
94+
if ( identifier instanceof Component component ) {
95+
final Generator componentIdentifierGenerator = component.createGenerator(
96+
creationContext.getDialect(),
97+
persistentClass.getRootClass(),
98+
persistentClass.getIdentifierProperty(),
99+
creationContext.getGeneratorSettings()
100+
);
101+
identifier.setCustomIdGeneratorCreator( context ->
102+
augmentWithReactiveGenerator( componentIdentifierGenerator, context, creationContext )
103+
);
104+
}
105+
else {
106+
identifier.setCustomIdGeneratorCreator( context ->
107+
augmentWithReactiveGenerator( customIdGeneratorCreator.createGenerator( context ), context, creationContext )
108+
);
109+
}
110+
}
111+
89112
public static Generator augmentWithReactiveGenerator(
90113
Generator generator,
91114
GeneratorCreationContext creationContext,
92115
RuntimeModelCreationContext runtimeModelCreationContext) {
93-
if ( generator instanceof SequenceStyleGenerator ) {
94-
final DatabaseStructure structure = ( (SequenceStyleGenerator) generator ).getDatabaseStructure();
116+
if ( generator instanceof SequenceStyleGenerator sequenceStyleGenerator) {
117+
final DatabaseStructure structure = sequenceStyleGenerator.getDatabaseStructure();
95118
if ( structure instanceof TableStructure ) {
96119
return initialize( (IdentifierGenerator) generator, new EmulatedSequenceReactiveIdentifierGenerator( (TableStructure) structure, runtimeModelCreationContext ), creationContext );
97120
}
@@ -100,16 +123,28 @@ public static Generator augmentWithReactiveGenerator(
100123
}
101124
throw LOG.unknownStructureType();
102125
}
103-
if ( generator instanceof TableGenerator ) {
126+
if ( generator instanceof TableGenerator tableGenerator ) {
104127
return initialize(
105128
(IdentifierGenerator) generator,
106-
new TableReactiveIdentifierGenerator( (TableGenerator) generator, runtimeModelCreationContext ),
129+
new TableReactiveIdentifierGenerator( tableGenerator, runtimeModelCreationContext ),
107130
creationContext
108131
);
109132
}
110133
if ( generator instanceof SelectGenerator ) {
111134
throw LOG.selectGeneratorIsNotSupportedInHibernateReactive();
112135
}
136+
if ( generator instanceof CompositeNestedGeneratedValueGenerator compositeNestedGeneratedValueGenerator ) {
137+
final ReactiveCompositeNestedGeneratedValueGenerator reactiveCompositeNestedGeneratedValueGenerator = new ReactiveCompositeNestedGeneratedValueGenerator(
138+
compositeNestedGeneratedValueGenerator,
139+
creationContext,
140+
runtimeModelCreationContext
141+
);
142+
return initialize(
143+
(IdentifierGenerator) generator,
144+
reactiveCompositeNestedGeneratedValueGenerator,
145+
creationContext
146+
);
147+
}
113148
//nothing to do
114149
return generator;
115150
}

0 commit comments

Comments
 (0)