Skip to content

Commit 909a8b0

Browse files
gavinkingbeikov
authored andcommitted
HHH-17934 sort out version handling in upsert()
Signed-off-by: Gavin King <gavin@hibernate.org>
1 parent ef0cc75 commit 909a8b0

File tree

3 files changed

+45
-25
lines changed

3 files changed

+45
-25
lines changed

hibernate-core/src/main/java/org/hibernate/dialect/SqlAstTranslatorWithMerge.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,11 @@ public MergeOperation createMergeOperation(OptionalTableUpdate optionalTableUpda
5050
);
5151
}
5252

53-
@Override
54-
public void visitOptionalTableUpdate(OptionalTableUpdate tableUpdate) {
55-
renderMergeStatement(tableUpdate);
56-
}
57-
53+
// @Override
54+
// public void visitOptionalTableUpdate(OptionalTableUpdate tableUpdate) {
55+
// renderMergeStatement(tableUpdate);
56+
// }
57+
//
5858
/**
5959
* Renders the OptionalTableUpdate as a MERGE query.
6060
*

hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,14 @@
3131
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
3232
import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper;
3333
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
34+
import org.hibernate.generator.BeforeExecutionGenerator;
35+
import org.hibernate.generator.Generator;
3436
import org.hibernate.graph.GraphSemantic;
3537
import org.hibernate.graph.spi.RootGraphImplementor;
3638
import org.hibernate.loader.ast.spi.CascadingFetchProfile;
3739
import org.hibernate.persister.collection.CollectionPersister;
3840
import org.hibernate.persister.entity.EntityPersister;
3941
import org.hibernate.proxy.LazyInitializer;
40-
import org.hibernate.generator.Generator;
41-
import org.hibernate.generator.BeforeExecutionGenerator;
4242
import org.hibernate.tuple.entity.EntityMetamodel;
4343

4444
import jakarta.transaction.SystemException;
@@ -173,37 +173,50 @@ public void update(String entityName, Object entity) {
173173
public void upsert(String entityName, Object entity) {
174174
checkOpen();
175175
final EntityPersister persister = getEntityPersister( entityName, entity );
176-
Object id = persister.getIdentifier( entity, this );
177-
Boolean knownTransient = persister.isTransient( entity, this );
178-
if ( knownTransient!=null && knownTransient ) {
179-
throw new TransientObjectException(
180-
"Object passed to upsert() has a null identifier: "
181-
+ persister.getEntityName() );
182-
// final Generator generator = persister.getGenerator();
183-
// if ( !generator.generatedOnExecution() ) {
184-
// id = ( (BeforeExecutionGenerator) generator).generate( this, entity, null, INSERT );
185-
// }
186-
}
176+
final Object id = idToUpsert( entity, persister );
187177
final Object[] state = persister.getValues( entity );
188-
final Object oldVersion;
178+
final Object oldVersion = versionToUpsert( entity, persister, state );
179+
persister.merge( id, state, null, false, null, oldVersion, entity, null, this );
180+
}
181+
182+
private Object versionToUpsert(Object entity, EntityPersister persister, Object[] state) {
189183
if ( persister.isVersioned() ) {
190-
oldVersion = persister.getVersion( entity );
191-
if ( oldVersion == null ) {
184+
final Object oldVersion = persister.getVersion( entity );
185+
final Boolean knownTransient =
186+
persister.getVersionMapping()
187+
.getUnsavedStrategy()
188+
.isUnsaved( oldVersion );
189+
if ( knownTransient != null && knownTransient ) {
192190
if ( seedVersion( entity, state, persister, this ) ) {
193191
persister.setValues( entity, state );
194192
}
193+
// this is a nonsense but avoids setting version restriction
194+
// parameter to null later on deep in the guts
195+
return state[persister.getVersionProperty()];
195196
}
196197
else {
197198
final Object newVersion = incrementVersion( entity, oldVersion, persister, this );
198199
setVersion( state, newVersion, persister );
199200
persister.setValues( entity, state );
201+
return oldVersion;
200202
}
201203
}
202204
else {
203-
oldVersion = null;
205+
return null;
204206
}
205-
persister.merge( id, state, null, false, null, oldVersion, entity, null, this );
206-
// persister.setIdentifier( entity, id, this );
207+
}
208+
209+
private Object idToUpsert(Object entity, EntityPersister persister) {
210+
final Object id = persister.getIdentifier( entity, this );
211+
final Boolean unsaved =
212+
persister.getIdentifierMapping()
213+
.getUnsavedStrategy()
214+
.isUnsaved( id );
215+
if ( unsaved != null && unsaved ) {
216+
throw new TransientObjectException( "Object passed to upsert() has an unsaved identifier value: "
217+
+ persister.getEntityName() );
218+
}
219+
return id;
207220
}
208221

209222

hibernate-core/src/test/java/org/hibernate/orm/test/stateless/UpsertVersionedTest.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
public class UpsertVersionedTest {
1616
@Test void test(SessionFactoryScope scope) {
1717
scope.inStatelessTransaction(s-> {
18-
s.upsert(new Record(123L,0L,"hello earth"));
18+
s.upsert(new Record(123L,null,"hello earth"));
1919
s.upsert(new Record(456L,2L,"hello mars"));
2020
});
2121
scope.inStatelessTransaction(s-> {
@@ -29,6 +29,13 @@ public class UpsertVersionedTest {
2929
assertEquals("goodbye earth",s.get(Record.class,123L).message);
3030
assertEquals("hello mars",s.get(Record.class,456L).message);
3131
});
32+
scope.inStatelessTransaction(s-> {
33+
s.upsert(new Record(456L,4L,"goodbye mars"));
34+
});
35+
scope.inStatelessTransaction(s-> {
36+
assertEquals("goodbye earth",s.get(Record.class,123L).message);
37+
assertEquals("goodbye mars",s.get(Record.class,456L).message);
38+
});
3239
}
3340
@Entity
3441
static class Record {

0 commit comments

Comments
 (0)