HHH-12738 - Session/EntityManager is closed in ForeignGenerator (JTA setup)
Add test case proving the issue does not replicate for either RESOURCE_LOCAL or JTA transactions
This commit is contained in:
parent
163cab99e2
commit
b3e0d363bd
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
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.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.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.jta.TestingJtaBootstrap;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
@TestForIssue(jiraKey = "HHH-12738")
|
||||
public class ForeignGeneratorJtaTest extends ForeignGeneratorResourceLocalTest {
|
||||
|
||||
@Override
|
||||
protected void addConfigOptions(Map options) {
|
||||
TestingJtaBootstrap.prepare( options );
|
||||
options.put( Environment.TRANSACTION_COORDINATOR_STRATEGY, "jta" );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,310 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.test.idgen.foreign;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
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.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-12738" )
|
||||
public class ForeignGeneratorResourceLocalTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] {
|
||||
Contract.class,
|
||||
Customer.class,
|
||||
CustomerContractRelation.class
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addRelationImplicitFlush() 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();
|
||||
} );
|
||||
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
|
||||
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 );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addRelationExplicitFlush() 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();
|
||||
} );
|
||||
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
|
||||
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 );
|
||||
|
||||
entityManager.flush();
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addRelationImplicitFlushOneTx() throws Exception {
|
||||
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
Contract contract = new Contract();
|
||||
|
||||
entityManager.persist( contract );
|
||||
|
||||
Customer customer = new Customer();
|
||||
|
||||
entityManager.persist( customer );
|
||||
|
||||
customer = entityManager.createQuery(
|
||||
"SELECT c " +
|
||||
"FROM Customer c " +
|
||||
" LEFT JOIN FETCH c.contractRelations " +
|
||||
" WHERE c.id = :customerId", Customer.class )
|
||||
.setParameter( "customerId", customer.getId() )
|
||||
.getSingleResult();
|
||||
|
||||
CustomerContractRelation relation = new CustomerContractRelation();
|
||||
relation.setContractId( customer.getId() );
|
||||
customer.addContractRelation( relation );
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity(name = "Contract")
|
||||
@Table(name = "CONTRACT")
|
||||
public static class Contract {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Customer")
|
||||
@Table(name = "CUSTOMER")
|
||||
public static class Customer {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
@OneToMany(mappedBy = "customer", fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE },
|
||||
orphanRemoval = true, targetEntity = CustomerContractRelation.class)
|
||||
private final Set<CustomerContractRelation> contractRelations = new HashSet<>();
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Set<CustomerContractRelation> getContractRelations() {
|
||||
return contractRelations;
|
||||
}
|
||||
|
||||
public boolean addContractRelation(CustomerContractRelation relation) {
|
||||
if ( relation != null ) {
|
||||
relation.setCustomer( this );
|
||||
return contractRelations.add( relation );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public static class CustomerContractId implements Serializable {
|
||||
private static final long serialVersionUID = 1115591676841551563L;
|
||||
|
||||
@Column(name = "CUSTOMERID", nullable = false)
|
||||
private Long customerId;
|
||||
|
||||
@Column(name = "CONTRACTID", nullable = false)
|
||||
private Long contractId;
|
||||
|
||||
public Long getCustomerId() {
|
||||
return customerId;
|
||||
}
|
||||
|
||||
public void setCustomerId(Long customerId) {
|
||||
this.customerId = customerId;
|
||||
}
|
||||
|
||||
public Long getContractId() {
|
||||
return contractId;
|
||||
}
|
||||
|
||||
public void setContractId(Long contractId) {
|
||||
this.contractId = contractId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ( ( contractId == null ) ? 0 : contractId.hashCode() );
|
||||
result = prime * result + ( ( customerId == null ) ? 0 : customerId.hashCode() );
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if ( this == obj ) {
|
||||
return true;
|
||||
}
|
||||
if ( obj == null ) {
|
||||
return false;
|
||||
}
|
||||
if ( getClass() != obj.getClass() ) {
|
||||
return false;
|
||||
}
|
||||
CustomerContractId other = (CustomerContractId) obj;
|
||||
if ( contractId == null ) {
|
||||
if ( other.contractId != null ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ( !contractId.equals( other.contractId ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( customerId == null ) {
|
||||
if ( other.customerId != null ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ( !customerId.equals( other.customerId ) ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "CustomerContractRelation")
|
||||
@Table(name = "CUSTOMER_CONTRACT_RELATION")
|
||||
public static class CustomerContractRelation {
|
||||
@EmbeddedId
|
||||
private final CustomerContractId id = new CustomerContractId();
|
||||
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
@Column(nullable = true, name = "SIGNEDONDATE")
|
||||
private Date signedOn;
|
||||
|
||||
@MapsId(value = "customerId")
|
||||
@JoinColumn(name = "CUSTOMERID", nullable = false)
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
private Customer customer;
|
||||
|
||||
public CustomerContractId getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Customer getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
public void setCustomer(Customer customer) {
|
||||
this.customer = customer;
|
||||
}
|
||||
|
||||
public Date getSignedOn() {
|
||||
return signedOn;
|
||||
}
|
||||
|
||||
public void setSignedOn(Date signedOn) {
|
||||
this.signedOn = signedOn;
|
||||
}
|
||||
|
||||
public Long getCustomerId() {
|
||||
return id.getCustomerId();
|
||||
}
|
||||
|
||||
public void setCustomerId(Long customerId) {
|
||||
id.setCustomerId( customerId );
|
||||
}
|
||||
|
||||
public Long getContractId() {
|
||||
return id.getContractId();
|
||||
}
|
||||
|
||||
public void setContractId(Long contractId) {
|
||||
id.setContractId( contractId );
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue