25
25
import org .hibernate .event .spi .EventSource ;
26
26
import org .hibernate .generator .BeforeExecutionGenerator ;
27
27
import org .hibernate .generator .Generator ;
28
+ import org .hibernate .id .Assigned ;
28
29
import org .hibernate .id .IdentifierGenerationException ;
29
30
import org .hibernate .jpa .event .spi .CallbackRegistry ;
30
31
import org .hibernate .jpa .event .spi .CallbackRegistryConsumer ;
@@ -122,27 +123,45 @@ protected CompletionStage<Void> reactiveSaveWithGeneratedId(
122
123
C context ,
123
124
EventSource source ,
124
125
boolean requiresImmediateIdAccess ) {
125
- callbackRegistry .preCreate ( entity );
126
-
127
- processIfSelfDirtinessTracker ( entity , SelfDirtinessTracker ::$$_hibernate_clearDirtyAttributes );
128
126
129
127
final EntityPersister persister = source .getEntityPersister ( entityName , entity );
130
128
final Generator generator = persister .getGenerator ();
131
- if ( !generator .generatedOnExecution () ) {
129
+ final boolean generatedOnExecution = generator .generatedOnExecution ( entity , source );
130
+ final Object generatedId ;
131
+ if ( generatedOnExecution ) {
132
+ // the id gets generated by the database
133
+ // and is not yet available
134
+ generatedId = null ;
135
+ }
136
+ else if ( generator instanceof Assigned ) {
137
+ // get it from the entity later, since we need
138
+ // the @PrePersist callback to happen first
139
+ generatedId = null ;
140
+ }
141
+ else {
142
+ // go ahead and generate id, and then set it to
143
+ // the entity instance, so it will be available
144
+ // to the entity in the @PrePersist callback
132
145
if ( generator instanceof ReactiveIdentifierGenerator ) {
133
146
return ( (ReactiveIdentifierGenerator <?>) generator )
134
147
.generate ( ( ReactiveConnectionSupplier ) source , entity )
135
148
.thenApply ( id -> castToIdentifierType ( id , persister ) )
136
- .thenCompose ( generatedId -> performSaveWithId ( entity , context , source , persister , generator , generatedId ) );
149
+ .thenCompose ( gid -> performSaveWithId (
150
+ entity ,
151
+ context ,
152
+ source ,
153
+ persister ,
154
+ generator ,
155
+ gid ,
156
+ requiresImmediateIdAccess ,
157
+ false
158
+ ) );
137
159
}
138
160
139
- final Object generatedId = ( (BeforeExecutionGenerator ) generator ).generate ( source , entity , null , INSERT );
140
- final Object id = castToIdentifierType ( generatedId , persister );
141
- return performSaveWithId ( entity , context , source , persister , generator , id );
142
- }
143
- else {
144
- return reactivePerformSave ( entity , null , persister , true , context , source , requiresImmediateIdAccess );
161
+ generatedId = ( (BeforeExecutionGenerator ) generator ).generate ( source , entity , null , INSERT );
145
162
}
163
+ final Object id = castToIdentifierType ( generatedId , persister );
164
+ return reactivePerformSave ( entity , id , persister , generatedOnExecution , context , source , requiresImmediateIdAccess );
146
165
}
147
166
148
167
private CompletionStage <Void > performSaveWithId (
@@ -151,7 +170,9 @@ private CompletionStage<Void> performSaveWithId(
151
170
EventSource source ,
152
171
EntityPersister persister ,
153
172
Generator generator ,
154
- Object generatedId ) {
173
+ Object generatedId ,
174
+ boolean requiresImmediateIdAccess ,
175
+ boolean generatedOnExecution ) {
155
176
if ( generatedId == null ) {
156
177
throw new IdentifierGenerationException ( "null id generated for: " + entity .getClass () );
157
178
}
@@ -166,7 +187,11 @@ private CompletionStage<Void> performSaveWithId(
166
187
generator .getClass ().getName ()
167
188
);
168
189
}
169
- return reactivePerformSave ( entity , generatedId , persister , false , context , source , true );
190
+ final boolean delayIdentityInserts =
191
+ !source .isTransactionInProgress ()
192
+ && !requiresImmediateIdAccess
193
+ && generatedOnExecution ;
194
+ return reactivePerformSave ( entity , generatedId , persister , false , context , source , delayIdentityInserts );
170
195
}
171
196
172
197
/**
@@ -196,6 +221,22 @@ protected CompletionStage<Void> reactivePerformSave(
196
221
EventSource source ,
197
222
boolean requiresImmediateIdAccess ) {
198
223
224
+ // call this after generation of an id,
225
+ // but before we retrieve an assigned id
226
+ callbackRegistry .preCreate ( entity );
227
+
228
+ processIfSelfDirtinessTracker ( entity , SelfDirtinessTracker ::$$_hibernate_clearDirtyAttributes );
229
+
230
+ if ( persister .getGenerator () instanceof Assigned ) {
231
+ id = persister .getIdentifier ( entity , source );
232
+ if ( id == null ) {
233
+ throw new IdentifierGenerationException (
234
+ "Identifier of entity '" + persister .getEntityName ()
235
+ + "' must be manually assigned before calling 'persist()'"
236
+ );
237
+ }
238
+ }
239
+
199
240
if ( LOG .isTraceEnabled () ) {
200
241
LOG .tracev ( "Saving {0}" , infoString ( persister , id , source .getFactory () ) );
201
242
}
@@ -268,8 +309,10 @@ protected CompletionStage<Void> reactivePerformSaveOrReplicate(
268
309
269
310
final Object id = key == null ? null : key .getIdentifier ();
270
311
271
- final boolean inTransaction = source .isTransactionInProgress ();
272
- final boolean shouldDelayIdentityInserts = !inTransaction && !requiresImmediateIdAccess ;
312
+ Generator generator = persister .getGenerator ();
313
+ final boolean shouldDelayIdentityInserts = !source .isTransactionInProgress ()
314
+ && !requiresImmediateIdAccess
315
+ && generator .generatedOnExecution ( entity , source );
273
316
final PersistenceContext persistenceContext = source .getPersistenceContextInternal ();
274
317
275
318
// Put a placeholder in entries, so we don't recurse back and try to save() the
0 commit comments