HHH-17934 sort out version handling in upsert()
Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
parent
ef0cc752c6
commit
909a8b0b4a
|
@ -50,11 +50,11 @@ public abstract class SqlAstTranslatorWithMerge<T extends JdbcOperation> extends
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
// @Override
|
||||||
public void visitOptionalTableUpdate(OptionalTableUpdate tableUpdate) {
|
// public void visitOptionalTableUpdate(OptionalTableUpdate tableUpdate) {
|
||||||
renderMergeStatement(tableUpdate);
|
// renderMergeStatement(tableUpdate);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
/**
|
/**
|
||||||
* Renders the OptionalTableUpdate as a MERGE query.
|
* Renders the OptionalTableUpdate as a MERGE query.
|
||||||
*
|
*
|
||||||
|
|
|
@ -31,14 +31,14 @@ import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||||
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
||||||
import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper;
|
import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper;
|
||||||
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
|
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.GraphSemantic;
|
||||||
import org.hibernate.graph.spi.RootGraphImplementor;
|
import org.hibernate.graph.spi.RootGraphImplementor;
|
||||||
import org.hibernate.loader.ast.spi.CascadingFetchProfile;
|
import org.hibernate.loader.ast.spi.CascadingFetchProfile;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.proxy.LazyInitializer;
|
import org.hibernate.proxy.LazyInitializer;
|
||||||
import org.hibernate.generator.Generator;
|
|
||||||
import org.hibernate.generator.BeforeExecutionGenerator;
|
|
||||||
import org.hibernate.tuple.entity.EntityMetamodel;
|
import org.hibernate.tuple.entity.EntityMetamodel;
|
||||||
|
|
||||||
import jakarta.transaction.SystemException;
|
import jakarta.transaction.SystemException;
|
||||||
|
@ -173,37 +173,50 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
|
||||||
public void upsert(String entityName, Object entity) {
|
public void upsert(String entityName, Object entity) {
|
||||||
checkOpen();
|
checkOpen();
|
||||||
final EntityPersister persister = getEntityPersister( entityName, entity );
|
final EntityPersister persister = getEntityPersister( entityName, entity );
|
||||||
Object id = persister.getIdentifier( entity, this );
|
final Object id = idToUpsert( entity, persister );
|
||||||
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[] state = persister.getValues( entity );
|
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() ) {
|
if ( persister.isVersioned() ) {
|
||||||
oldVersion = persister.getVersion( entity );
|
final Object oldVersion = persister.getVersion( entity );
|
||||||
if ( oldVersion == null ) {
|
final Boolean knownTransient =
|
||||||
|
persister.getVersionMapping()
|
||||||
|
.getUnsavedStrategy()
|
||||||
|
.isUnsaved( oldVersion );
|
||||||
|
if ( knownTransient != null && knownTransient ) {
|
||||||
if ( seedVersion( entity, state, persister, this ) ) {
|
if ( seedVersion( entity, state, persister, this ) ) {
|
||||||
persister.setValues( entity, state );
|
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 {
|
else {
|
||||||
final Object newVersion = incrementVersion( entity, oldVersion, persister, this );
|
final Object newVersion = incrementVersion( entity, oldVersion, persister, this );
|
||||||
setVersion( state, newVersion, persister );
|
setVersion( state, newVersion, persister );
|
||||||
persister.setValues( entity, state );
|
persister.setValues( entity, state );
|
||||||
|
return oldVersion;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ import static org.junit.Assert.assertEquals;
|
||||||
public class UpsertVersionedTest {
|
public class UpsertVersionedTest {
|
||||||
@Test void test(SessionFactoryScope scope) {
|
@Test void test(SessionFactoryScope scope) {
|
||||||
scope.inStatelessTransaction(s-> {
|
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"));
|
s.upsert(new Record(456L,2L,"hello mars"));
|
||||||
});
|
});
|
||||||
scope.inStatelessTransaction(s-> {
|
scope.inStatelessTransaction(s-> {
|
||||||
|
@ -29,6 +29,13 @@ public class UpsertVersionedTest {
|
||||||
assertEquals("goodbye earth",s.get(Record.class,123L).message);
|
assertEquals("goodbye earth",s.get(Record.class,123L).message);
|
||||||
assertEquals("hello mars",s.get(Record.class,456L).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
|
@Entity
|
||||||
static class Record {
|
static class Record {
|
||||||
|
|
Loading…
Reference in New Issue