HHH-12738 - Session/EntityManager is closed in ForeignGenerator (JTA setup)

This commit is contained in:
Vlad Mihalcea 2018-06-27 14:55:48 +03:00
parent c69038d476
commit 07738c4d89
3 changed files with 72 additions and 38 deletions

View File

@ -2107,7 +2107,7 @@ public final class SessionImpl
@Override @Override
public boolean contains(String entityName, Object object) { public boolean contains(String entityName, Object object) {
checkOpen(); checkOpenOrWaitingForAutoClose();
checkTransactionSynchStatus(); checkTransactionSynchStatus();
if ( object == null ) { if ( object == null ) {

View File

@ -6,35 +6,12 @@
*/ */
package org.hibernate.test.idgen.foreign; package org.hibernate.test.idgen.foreign;
import java.io.Serializable;
import java.util.Date;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MapsId;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.hibernate.cfg.Environment; import org.hibernate.cfg.Environment;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.hibernate.testing.TestForIssue; import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.jta.TestingJtaBootstrap; import org.hibernate.testing.jta.TestingJtaBootstrap;
import org.junit.Test;
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
/** /**
* @author Vlad Mihalcea * @author Vlad Mihalcea

View File

@ -15,6 +15,8 @@ import javax.persistence.Column;
import javax.persistence.Embeddable; import javax.persistence.Embeddable;
import javax.persistence.EmbeddedId; import javax.persistence.EmbeddedId;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.FetchType; import javax.persistence.FetchType;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Id;
@ -36,15 +38,15 @@ import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
/** /**
* @author Vlad Mihalcea * @author Vlad Mihalcea
*/ */
@TestForIssue( jiraKey = "HHH-12738" ) @TestForIssue(jiraKey = "HHH-12738")
public class ForeignGeneratorResourceLocalTest extends BaseEntityManagerFunctionalTestCase { public class ForeignGeneratorResourceLocalTest extends BaseEntityManagerFunctionalTestCase {
@Override @Override
protected Class<?>[] getAnnotatedClasses() { protected Class<?>[] getAnnotatedClasses() {
return new Class[] { return new Class[] {
Contract.class, Contract.class,
Customer.class, Customer.class,
CustomerContractRelation.class CustomerContractRelation.class
}; };
} }
@ -128,12 +130,12 @@ public class ForeignGeneratorResourceLocalTest extends BaseEntityManagerFunction
entityManager.persist( customer ); entityManager.persist( customer );
customer = entityManager.createQuery( customer = entityManager.createQuery(
"SELECT c " + "SELECT c " +
"FROM Customer c " + "FROM Customer c " +
" LEFT JOIN FETCH c.contractRelations " + " LEFT JOIN FETCH c.contractRelations " +
" WHERE c.id = :customerId", Customer.class ) " WHERE c.id = :customerId", Customer.class )
.setParameter( "customerId", customer.getId() ) .setParameter( "customerId", customer.getId() )
.getSingleResult(); .getSingleResult();
CustomerContractRelation relation = new CustomerContractRelation(); CustomerContractRelation relation = new CustomerContractRelation();
relation.setContractId( customer.getId() ); relation.setContractId( customer.getId() );
@ -141,6 +143,62 @@ public class ForeignGeneratorResourceLocalTest extends BaseEntityManagerFunction
} ); } );
} }
@Test
public void addRelationImplicitFlushCloseEntityManager() throws Exception {
Long contractId = doInJPA( this::entityManagerFactory, entityManager -> {
Contract contract = new Contract();
entityManager.persist( contract );
return contract.getId();
} );
Long customerId = doInJPA( this::entityManagerFactory, entityManager -> {
Customer customer = new Customer();
entityManager.persist( customer );
return customer.getId();
} );
EntityManager entityManager = null;
EntityTransaction txn = null;
try {
entityManager = entityManagerFactory().createEntityManager();
txn = entityManager.getTransaction();
txn.begin();
Customer customer = entityManager.createQuery(
"SELECT c " +
"FROM Customer c " +
" LEFT JOIN FETCH c.contractRelations " +
" WHERE c.id = :customerId", Customer.class )
.setParameter( "customerId", customerId )
.getSingleResult();
CustomerContractRelation relation = new CustomerContractRelation();
relation.setContractId( contractId );
customer.addContractRelation( relation );
//Close the EntityManager
entityManager.close();
//And, afterward commit the currently running Tx.
//This might happen in JTA environments where the Tx is committed by the JTA TM.
txn.commit();
}
catch (Throwable t) {
if ( txn != null && txn.isActive() ) {
try {
txn.rollback();
}
catch (Exception e) {
log.error( "Rollback failure", e );
}
}
throw t;
}
}
@Entity(name = "Contract") @Entity(name = "Contract")
@Table(name = "CONTRACT") @Table(name = "CONTRACT")
public static class Contract { public static class Contract {
@ -160,13 +218,12 @@ public class ForeignGeneratorResourceLocalTest extends BaseEntityManagerFunction
@Entity(name = "Customer") @Entity(name = "Customer")
@Table(name = "CUSTOMER") @Table(name = "CUSTOMER")
public static class Customer { public static class Customer {
@Id
@GeneratedValue
private Long id;
@OneToMany(mappedBy = "customer", fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE }, @OneToMany(mappedBy = "customer", fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE },
orphanRemoval = true, targetEntity = CustomerContractRelation.class) orphanRemoval = true, targetEntity = CustomerContractRelation.class)
private final Set<CustomerContractRelation> contractRelations = new HashSet<>(); private final Set<CustomerContractRelation> contractRelations = new HashSet<>();
@Id
@GeneratedValue
private Long id;
public Long getId() { public Long getId() {
return id; return id;