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 committed by Christian Beikov
parent ef0cc752c6
commit 909a8b0b4a
3 changed files with 45 additions and 25 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

@ -31,14 +31,14 @@ 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.generator.BeforeExecutionGenerator;
import org.hibernate.generator.Generator;
import org.hibernate.graph.GraphSemantic;
import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.loader.ast.spi.CascadingFetchProfile;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.generator.Generator;
import org.hibernate.generator.BeforeExecutionGenerator;
import org.hibernate.tuple.entity.EntityMetamodel;
import jakarta.transaction.SystemException;
@ -173,37 +173,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.merge( id, state, null, false, null, oldVersion, entity, null, 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.merge( id, state, null, false, null, oldVersion, entity, null, 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 {