HHH-10246 - Fix Envers usage of JoinColumn with NaturalId.

This commit is contained in:
Chris Cranford 2016-05-13 14:19:01 -05:00
parent 18a068ab5d
commit 9dca4b82ae
5 changed files with 418 additions and 3 deletions

View File

@ -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(),

View File

@ -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 +
'}';
}
}

View File

@ -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 +
'}';
}
}

View File

@ -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 +
'}';
}
}

View File

@ -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 );
}
}