HHH-17934 sort out version handling in upsert()

Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
Gavin King 2024-04-11 13:55:52 +02:00
parent 17df9bedf5
commit e620fbb892
3 changed files with 43 additions and 24 deletions

View File

@ -50,11 +50,11 @@ public abstract class SqlAstTranslatorWithMerge<T extends JdbcOperation> extends
);
}
@Override
public void visitOptionalTableUpdate(OptionalTableUpdate tableUpdate) {
renderMergeStatement(tableUpdate);
}
// @Override
// public void visitOptionalTableUpdate(OptionalTableUpdate tableUpdate) {
// renderMergeStatement(tableUpdate);
// }
//
/**
* Renders the OptionalTableUpdate as a MERGE query.
*

View File

@ -30,7 +30,6 @@ import org.hibernate.engine.spi.PersistentAttributeInterceptable;
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper;
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
import org.hibernate.event.spi.AutoFlushEvent;
import org.hibernate.generator.BeforeExecutionGenerator;
import org.hibernate.generator.Generator;
import org.hibernate.generator.values.GeneratedValues;
@ -177,37 +176,50 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
public void upsert(String entityName, Object entity) {
checkOpen();
final EntityPersister persister = getEntityPersister( entityName, entity );
Object id = persister.getIdentifier( entity, this );
Boolean knownTransient = persister.isTransient( entity, this );
if ( knownTransient!=null && knownTransient ) {
throw new TransientObjectException(
"Object passed to upsert() has a null identifier: "
+ persister.getEntityName() );
// final Generator generator = persister.getGenerator();
// if ( !generator.generatedOnExecution() ) {
// id = ( (BeforeExecutionGenerator) generator).generate( this, entity, null, INSERT );
// }
}
final Object id = idToUpsert( entity, persister );
final Object[] state = persister.getValues( entity );
final Object oldVersion;
final Object oldVersion = versionToUpsert( entity, persister, state );
persister.getMergeCoordinator().update( entity, id, null, state, oldVersion, null, null, false, this );
}
private Object versionToUpsert(Object entity, EntityPersister persister, Object[] state) {
if ( persister.isVersioned() ) {
oldVersion = persister.getVersion( entity );
if ( oldVersion == null ) {
final Object oldVersion = persister.getVersion( entity );
final Boolean knownTransient =
persister.getVersionMapping()
.getUnsavedStrategy()
.isUnsaved( oldVersion );
if ( knownTransient != null && knownTransient ) {
if ( seedVersion( entity, state, persister, this ) ) {
persister.setValues( entity, state );
}
// this is a nonsense but avoids setting version restriction
// parameter to null later on deep in the guts
return state[persister.getVersionProperty()];
}
else {
final Object newVersion = incrementVersion( entity, oldVersion, persister, this );
setVersion( state, newVersion, persister );
persister.setValues( entity, state );
return oldVersion;
}
}
else {
oldVersion = null;
return null;
}
persister.getMergeCoordinator().update( entity, id, null, state, oldVersion, null, null, false, this );
// persister.setIdentifier( entity, id, this );
}
private Object idToUpsert(Object entity, EntityPersister persister) {
final Object id = persister.getIdentifier( entity, this );
final Boolean unsaved =
persister.getIdentifierMapping()
.getUnsavedStrategy()
.isUnsaved( id );
if ( unsaved != null && unsaved ) {
throw new TransientObjectException( "Object passed to upsert() has an unsaved identifier value: "
+ persister.getEntityName() );
}
return id;
}

View File

@ -15,7 +15,7 @@ import static org.junit.Assert.assertEquals;
public class UpsertVersionedTest {
@Test void test(SessionFactoryScope scope) {
scope.inStatelessTransaction(s-> {
s.upsert(new Record(123L,0L,"hello earth"));
s.upsert(new Record(123L,null,"hello earth"));
s.upsert(new Record(456L,2L,"hello mars"));
});
scope.inStatelessTransaction(s-> {
@ -29,6 +29,13 @@ public class UpsertVersionedTest {
assertEquals("goodbye earth",s.get(Record.class,123L).message);
assertEquals("hello mars",s.get(Record.class,456L).message);
});
scope.inStatelessTransaction(s-> {
s.upsert(new Record(456L,4L,"goodbye mars"));
});
scope.inStatelessTransaction(s-> {
assertEquals("goodbye earth",s.get(Record.class,123L).message);
assertEquals("goodbye mars",s.get(Record.class,456L).message);
});
}
@Entity
static class Record {