revert back changes in 'org.hibernate.test.cascade'

This commit is contained in:
Nathan Xu 2020-02-18 18:29:20 -05:00 committed by Steve Ebersole
parent 30bfe89246
commit db50e046e2
9 changed files with 150 additions and 58 deletions

View File

@ -14,34 +14,42 @@ public enum CascadeType {
* Includes all types listed here.
*/
ALL,
/**
* Corresponds to {@link javax.persistence.CascadeType#PERSIST}.
*/
PERSIST,
/**
* Corresponds to {@link javax.persistence.CascadeType#MERGE}.
*/
MERGE,
/**
* Corresponds to {@link javax.persistence.CascadeType#REMOVE}.
*/
REMOVE,
/**
* Corresponds to {@link javax.persistence.CascadeType#REFRESH}.
*/
REFRESH,
/**
* Corresponds to the Hibernate native DELETE action.
*/
DELETE,
/**
* Corresponds to the Hibernate native SAVE_UPDATE (direct reattachment) action.
*/
SAVE_UPDATE,
/**
* Corresponds to the Hibernate native REPLICATE action.
*/
REPLICATE,
/**
* Hibernate originally handled orphan removal as a specialized cascade.
*
@ -49,10 +57,12 @@ public enum CascadeType {
*/
@Deprecated
DELETE_ORPHAN,
/**
* Corresponds to the Hibernate native LOCK action.
*/
LOCK,
/**
* JPA originally planned on calling DETACH EVICT.
*
@ -60,6 +70,7 @@ public enum CascadeType {
*/
@Deprecated
EVICT,
/**
* Corresponds to {@link javax.persistence.CascadeType#DETACH}.
*/

View File

@ -34,7 +34,6 @@ import org.hibernate.sql.exec.spi.JdbcParameterBinding;
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.exec.spi.JdbcSelect;
import org.hibernate.sql.results.internal.RowTransformerPassThruImpl;
import org.jboss.logging.Logger;
/**
@ -63,11 +62,7 @@ public class SingleIdEntityLoaderDynamicBatch<T> extends SingleIdEntityLoaderSup
final int numberOfIds = ArrayHelper.countNonNull( batchIds );
if ( numberOfIds <= 1 ) {
if ( singleIdLoader == null ) {
singleIdLoader = new SingleIdEntityLoaderStandardImpl<>( getLoadable(), session.getFactory() );
singleIdLoader.prepare();
}
initializeSingleIdLoaderIfNeeded( session );
final T result = singleIdLoader.load( pkValue, lockOptions, session );
if ( result == null ) {
@ -187,6 +182,14 @@ public class SingleIdEntityLoaderDynamicBatch<T> extends SingleIdEntityLoaderSup
Object entityInstance,
LockOptions lockOptions,
SharedSessionContractImplementor session) {
initializeSingleIdLoaderIfNeeded( session );
return singleIdLoader.load( pkValue, entityInstance, lockOptions, session );
}
private void initializeSingleIdLoaderIfNeeded(SharedSessionContractImplementor session) {
if ( singleIdLoader == null ) {
singleIdLoader = new SingleIdEntityLoaderStandardImpl<>( getLoadable(), session.getFactory() );
singleIdLoader.prepare();
}
}
}

View File

@ -136,6 +136,11 @@ public class SingleIdLoadPlan<T> implements SingleEntityLoadPlan {
return entityInstance;
}
@Override
public Object getEntityId() {
return restrictedValue;
}
@Override
public QueryOptions getQueryOptions() {
return QueryOptions.NONE;

View File

@ -23,7 +23,8 @@ public interface SingleIdEntityLoader<T> extends SingleEntityLoader<T> {
/**
* Load by primary key value, populating the passed entity instance. Used to initialize an uninitialized
* bytecode-proxy. The passed instance is the enhanced proxy
* bytecode-proxy or {@link org.hibernate.event.spi.LoadEvent} handling.
* The passed instance is the enhanced proxy or the entity to be loaded.
*/
T load(Object pkValue, Object entityInstance, LockOptions lockOptions, SharedSessionContractImplementor session);

View File

@ -4470,7 +4470,12 @@ public abstract class AbstractEntityPersister
LOG.tracev( "Fetching entity: {0}", MessageHelper.infoString( this, id, getFactory() ) );
}
return singleIdEntityLoader.load( id, lockOptions, session );
if ( optionalObject == null ) {
return singleIdEntityLoader.load( id, lockOptions, session );
}
else {
return singleIdEntityLoader.load( id, optionalObject, lockOptions, session );
}
}
public SingleIdEntityLoader getSingleIdEntityLoader() {

View File

@ -158,7 +158,7 @@ public class JdbcSelectExecutorStandardImpl implements JdbcSelectExecutor {
@Override
public Object getEffectiveOptionalId() {
return null;
return executionContext.getEntityId();
}
@Override

View File

@ -45,6 +45,10 @@ public interface ExecutionContext {
return null;
}
default Object getEntityId() {
return null;
}
default void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
// by default do nothing
}

View File

@ -398,8 +398,9 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
// this isEntityReturn bit is just for entity loaders, not hql/criteria
if ( isEntityReturn() ) {
final Object requestedEntityId = rowProcessingState.getJdbcValuesSourceProcessingState().getProcessingOptions().getEffectiveOptionalId();
if ( requestedEntityId != null && requestedEntityId.equals( entityKey.getIdentifier() ) ) {
entityInstance = rowProcessingState.getJdbcValuesSourceProcessingState().getProcessingOptions().getEffectiveOptionalObject();
final Object optionalEntityInstance = rowProcessingState.getJdbcValuesSourceProcessingState().getProcessingOptions().getEffectiveOptionalObject();
if ( requestedEntityId != null && optionalEntityInstance != null && requestedEntityId.equals( entityKey.getIdentifier() ) ) {
entityInstance = optionalEntityInstance;
}
}
}

View File

@ -6,20 +6,30 @@
*/
package org.hibernate.orm.test.cascade;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.util.Date;
import java.util.Iterator;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.FailureExpected;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.Assert.assertEquals;
/**
* Implementation of RefreshTest.
@ -27,61 +37,113 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
* @author Steve Ebersole
*/
@DomainModel(
xmlMappings = {
"org/hibernate/orm/test/cascade/Job.hbm.xml",
"org/hibernate/orm/test/cascade/JobBatch.hbm.xml"
}
annotatedClasses = {
RefreshTest.Job.class,
RefreshTest.JobBatch.class
}
)
@SessionFactory
@FailureExpected( reason = "This should be fixed by Nathan PR")
public class RefreshTest {
@Test
public void testRefreshCascade(SessionFactoryScope scope) {
private JobBatch batch;
@BeforeEach
void setUp(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
JobBatch batch = new JobBatch( new Date() );
batch.createJob().setProcessingInstructions( "Just do it!" );
batch.createJob().setProcessingInstructions( "I know you can do it!" );
session -> {
batch = new JobBatch( new Date() );
batch.createJob().processingInstructions = "Just do it!";
batch.createJob().processingInstructions = "I know you can do it!";
// write the stuff to the database; at this stage all job.status values are zero
session.persist( batch );
session.flush();
// write the stuff to the database; at this stage all job.status values are zero
session.save( batch );
}
);
// behind the session's back, let's modify the statuses
updateStatuses( session );
// behind the session's back, let's modify the statuses to one
scope.inSession( this::updateStatuses );
}
// Now lets refresh the persistent batch, and see if the refresh cascaded to the jobs collection elements
session.refresh( batch );
Iterator itr = batch.getJobs().iterator();
while ( itr.hasNext() ) {
Job job = (Job) itr.next();
assertEquals( 1, job.getStatus(), "Jobs not refreshed!" );
}
}
@Test
void testRefreshCascade(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.refresh( batch );
batch.jobs.forEach( job -> assertEquals( "Jobs not refreshed!", 1, job.status ) );
}
);
}
private void updateStatuses(final SessionImplementor session) {
session.doWork(
connection -> {
PreparedStatement stmnt = null;
try {
stmnt = session.getJdbcCoordinator().getStatementPreparer().prepareStatement(
"UPDATE T_JOB SET JOB_STATUS = 1" );
session.getJdbcCoordinator().getResultSetReturn().executeUpdate( stmnt );
}
finally {
if ( stmnt != null ) {
try {
session.getJdbcCoordinator().getResourceRegistry().release( stmnt );
}
catch (Throwable ignore) {
}
connection -> {
Statement stmnt = null;
try {
stmnt = session.getJdbcCoordinator().getStatementPreparer().createStatement();
stmnt.execute( "UPDATE T_JOB SET JOB_STATUS = 1" );
}
finally {
if ( stmnt != null ) {
try {
session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release( stmnt );
}
catch( Throwable ignore ) {
}
}
}
}
);
}
@Entity( name = "Job" )
@Table( name = "T_JOB" )
static class Job {
@Id @GeneratedValue
Long id;
@ManyToOne( fetch = FetchType.LAZY )
JobBatch batch;
@Column( name = "PI", nullable = false )
String processingInstructions;
@Column( name = "JOB_STATUS", nullable = false )
int status;
Job() {}
Job(JobBatch batch) {
this.batch = batch;
}
}
@Entity( name = "JobBatch" )
@Table( name = "T_JOB_BATCH" )
static class JobBatch {
@Id @GeneratedValue
Long id;
@Column( nullable = false )
@Temporal( TemporalType.TIMESTAMP )
Date batchDate;
@OneToMany( mappedBy = "batch", fetch = FetchType.LAZY, cascade = CascadeType.ALL )
@Fetch( FetchMode.SELECT )
Set<Job> jobs = new HashSet<>();
JobBatch() {}
JobBatch(Date batchDate) {
this.batchDate = batchDate;
}
Job createJob() {
Job job = new Job( this );
jobs.add( job );
return job;
}
}
}