HHH-10246 - Fix Envers usage of JoinColumn with NaturalId.
This commit is contained in:
parent
18a068ab5d
commit
9dca4b82ae
|
@ -10,6 +10,7 @@ import java.util.HashMap;
|
|||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.dom4j.Element;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
|
@ -34,6 +35,7 @@ import org.hibernate.mapping.Join;
|
|||
import org.hibernate.mapping.OneToOne;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.SyntheticProperty;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.mapping.Value;
|
||||
import org.hibernate.service.ServiceRegistry;
|
||||
|
@ -43,11 +45,8 @@ import org.hibernate.type.ManyToOneType;
|
|||
import org.hibernate.type.OneToOneType;
|
||||
import org.hibernate.type.TimestampType;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.dom4j.Element;
|
||||
|
||||
/**
|
||||
* @author Adam Warski (adam at warski dot org)
|
||||
* @author Sebastian Komander
|
||||
|
@ -56,6 +55,7 @@ import org.dom4j.Element;
|
|||
* @author Hernán Chanfreau
|
||||
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
|
||||
* @author Michal Skowronek (mskowr at o2 dot pl)
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
public final class AuditMetadataGenerator {
|
||||
private static final EnversMessageLogger LOG = Logger.getMessageLogger(
|
||||
|
@ -368,6 +368,14 @@ public final class AuditMetadataGenerator {
|
|||
final String propertyName = property.getName();
|
||||
final PropertyAuditingData propertyAuditingData = auditingData.getPropertyAuditingData( propertyName );
|
||||
if ( propertyAuditingData != null ) {
|
||||
// HHH-10246
|
||||
// Verifies if a mapping exists using a @JoinColumn against a @NaturalId field
|
||||
// and if so, this eliminates the mapping property as it isn't needed.
|
||||
if ( property instanceof SyntheticProperty ) {
|
||||
if ( property.getValue().isAlternateUniqueKey() ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
addValue(
|
||||
parent,
|
||||
property.getValue(),
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* 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.envers.test.integration.naturalid;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.JoinColumns;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
||||
import org.hibernate.envers.Audited;
|
||||
|
||||
/**
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
@Entity
|
||||
@Audited
|
||||
public class Account implements Serializable {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Integer id;
|
||||
|
||||
@Audited
|
||||
@ManyToOne
|
||||
@JoinColumns({
|
||||
@JoinColumn(name = "customer_customernumber", referencedColumnName = "customerNumber"),
|
||||
@JoinColumn(name = "customer_customername", referencedColumnName = "name")
|
||||
})
|
||||
private Customer customer;
|
||||
|
||||
Account() {
|
||||
|
||||
}
|
||||
|
||||
public Account(Integer id, Customer customer) {
|
||||
this.id = id;
|
||||
this.customer = customer;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Customer getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
public void setCustomer(Customer customer) {
|
||||
this.customer = customer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result;
|
||||
result = ( id != null ? id.hashCode() : 0 );
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if ( obj == this ) {
|
||||
return true;
|
||||
}
|
||||
if ( !(obj instanceof Account)) {
|
||||
return false;
|
||||
}
|
||||
Account that = (Account) obj;
|
||||
if ( id != null ? !id.equals( that.id ) : that.id != null ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Account{" +
|
||||
"id=" + id +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* 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.envers.test.integration.naturalid;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
|
||||
import org.hibernate.annotations.NaturalId;
|
||||
import org.hibernate.envers.Audited;
|
||||
|
||||
/**
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
@Entity
|
||||
@Audited
|
||||
public class Customer implements Serializable {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Integer id;
|
||||
|
||||
@NaturalId
|
||||
private String customerNumber;
|
||||
|
||||
@NaturalId
|
||||
private String name;
|
||||
|
||||
@Audited
|
||||
@OneToMany(mappedBy = "customer")
|
||||
private Collection<Account> accounts = new ArrayList<Account>();
|
||||
|
||||
@OneToMany(mappedBy = "customer", cascade = CascadeType.ALL)
|
||||
private Set<Device> devices = new HashSet<Device>();
|
||||
|
||||
Customer() {
|
||||
|
||||
}
|
||||
|
||||
Customer(Integer id, String customerNumber, String name) {
|
||||
this.id = id;
|
||||
this.customerNumber = customerNumber;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getCustomerNumber() {
|
||||
return customerNumber;
|
||||
}
|
||||
|
||||
public void setCustomerNumber(String customerNumber) {
|
||||
this.customerNumber = customerNumber;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Collection<Account> getAccounts() {
|
||||
return accounts;
|
||||
}
|
||||
|
||||
public void setAccounts(Collection<Account> accounts) {
|
||||
this.accounts = accounts;
|
||||
}
|
||||
|
||||
public Set<Device> getDevices() {
|
||||
return devices;
|
||||
}
|
||||
|
||||
public void setDevices(Set<Device> devices) {
|
||||
this.devices = devices;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result;
|
||||
result = ( id != null ? id.hashCode() : 0 );
|
||||
result = 31 * result + ( customerNumber != null ? customerNumber.hashCode() : 0 );
|
||||
result = 31 * result + ( name != null ? name.hashCode() : 0 );
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if ( obj == this ) {
|
||||
return true;
|
||||
}
|
||||
if ( !( obj instanceof Customer ) ) {
|
||||
return false;
|
||||
}
|
||||
Customer that = (Customer) obj;
|
||||
if ( id != null ? !id.equals( that.id ) : that.id != null ) {
|
||||
return false;
|
||||
}
|
||||
if ( name != null ? !name.equals( that.name ) : that.name != null ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Customer{" +
|
||||
"id=" + id +
|
||||
", name='" + name + '\'' +
|
||||
", customerNumber='" + customerNumber + '\'' +
|
||||
", accounts=" + accounts +
|
||||
", devices=" + devices +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* 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.envers.test.integration.naturalid;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.ForeignKey;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
|
||||
import org.hibernate.envers.Audited;
|
||||
|
||||
/**
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
@Entity
|
||||
@Audited
|
||||
public class Device implements Serializable {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Integer id;
|
||||
|
||||
@Audited
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "customer_id", foreignKey = @ForeignKey(name = "fk_dev_cust_id"))
|
||||
private Customer customer;
|
||||
|
||||
Device() {
|
||||
|
||||
}
|
||||
|
||||
public Device(Integer id, Customer customer) {
|
||||
this.id = id;
|
||||
this.customer = customer;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Customer getCustomer() {
|
||||
return customer;
|
||||
}
|
||||
|
||||
public void setCustomer(Customer customer) {
|
||||
this.customer = customer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result;
|
||||
result = ( id != null ? id.hashCode() : 0 );
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if ( obj == this ) {
|
||||
return true;
|
||||
}
|
||||
if ( !( obj instanceof Device ) ) {
|
||||
return false;
|
||||
}
|
||||
Device that = (Device) obj;
|
||||
if ( id != null ? !id.equals( that.id ) : that.id != null ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Device{" +
|
||||
"id=" + id +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* 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.envers.test.integration.naturalid;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase;
|
||||
import org.hibernate.envers.test.Priority;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Chris Cranford
|
||||
*/
|
||||
@TestForIssue(jiraKey = "HHH-10246")
|
||||
public class JoinColumnNaturalIdTest extends BaseEnversJPAFunctionalTestCase {
|
||||
private Integer customerId;
|
||||
private Integer deviceId;
|
||||
private Integer accountId;
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Account.class,
|
||||
Customer.class,
|
||||
Device.class
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
@Priority(10)
|
||||
public void initData() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
try {
|
||||
// Revision 1
|
||||
em.getTransaction().begin();
|
||||
Customer customer = new Customer();
|
||||
customer.setCustomerNumber( "1234567" );
|
||||
customer.setName( "ACME" );
|
||||
em.persist( customer );
|
||||
em.getTransaction().commit();
|
||||
customerId = customer.getId();
|
||||
// Revision 2
|
||||
em.getTransaction().begin();
|
||||
Device device = new Device();
|
||||
device.setCustomer( customer );
|
||||
Account account = new Account();
|
||||
account.setCustomer( customer );
|
||||
em.persist( account );
|
||||
em.persist( device );
|
||||
em.getTransaction().commit();
|
||||
accountId = account.getId();
|
||||
deviceId = device.getId();
|
||||
// Revision 3
|
||||
em.getTransaction().begin();
|
||||
em.remove( account );
|
||||
em.getTransaction().commit();
|
||||
}
|
||||
finally {
|
||||
em.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRevisionCounts() {
|
||||
assertEquals( 3, getAuditReader().getRevisions( Customer.class, customerId ).size() );
|
||||
assertEquals( 2, getAuditReader().getRevisions( Account.class, accountId ).size() );
|
||||
assertEquals( 1, getAuditReader().getRevisions( Device.class, deviceId ).size() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRevisionHistoryOfCustomer() {
|
||||
final Customer customer = new Customer( customerId, "1234567", "ACME" );
|
||||
Customer rev1 = getAuditReader().find( Customer.class, customerId, 1 );
|
||||
assertEquals( customer, rev1 );
|
||||
|
||||
final Account account = new Account( accountId, customer );
|
||||
final Device device = new Device( deviceId, customer );
|
||||
customer.getAccounts().add( account );
|
||||
customer.getDevices().add( device );
|
||||
Customer rev2 = getAuditReader().find( Customer.class, customerId, 2 );
|
||||
assertEquals( customer, rev2 );
|
||||
|
||||
customer.getAccounts().clear();
|
||||
Customer rev3 = getAuditReader().find( Customer.class, customerId, 3 );
|
||||
assertEquals( customer, rev3 );
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue