HHH-3602: bug fix with test (generating a CollectionChangeWorkUnit for the proper entity in case a relation is owned by a superclass, when inheritance is used)
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@15565 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
edf3822cfb
commit
044efaeeb3
|
@ -41,6 +41,7 @@ import org.hibernate.envers.tools.Tools;
|
||||||
import org.hibernate.cfg.Configuration;
|
import org.hibernate.cfg.Configuration;
|
||||||
import org.hibernate.collection.PersistentCollection;
|
import org.hibernate.collection.PersistentCollection;
|
||||||
import org.hibernate.engine.CollectionEntry;
|
import org.hibernate.engine.CollectionEntry;
|
||||||
|
import org.hibernate.engine.SessionImplementor;
|
||||||
import org.hibernate.event.AbstractCollectionEvent;
|
import org.hibernate.event.AbstractCollectionEvent;
|
||||||
import org.hibernate.event.Initializable;
|
import org.hibernate.event.Initializable;
|
||||||
import org.hibernate.event.PostCollectionRecreateEvent;
|
import org.hibernate.event.PostCollectionRecreateEvent;
|
||||||
|
@ -66,7 +67,8 @@ public class AuditEventListener implements PostInsertEventListener, PostUpdateEv
|
||||||
private AuditConfiguration verCfg;
|
private AuditConfiguration verCfg;
|
||||||
|
|
||||||
private void generateBidirectionalCollectionChangeWorkUnits(AuditSync verSync, EntityPersister entityPersister,
|
private void generateBidirectionalCollectionChangeWorkUnits(AuditSync verSync, EntityPersister entityPersister,
|
||||||
String entityName, Object[] newState, Object[] oldState) {
|
String entityName, Object[] newState, Object[] oldState,
|
||||||
|
SessionImplementor session) {
|
||||||
// Checking if this is enabled in configuration ...
|
// Checking if this is enabled in configuration ...
|
||||||
if (!verCfg.getGlobalCfg().isGenerateRevisionsForCollections()) {
|
if (!verCfg.getGlobalCfg().isGenerateRevisionsForCollections()) {
|
||||||
return;
|
return;
|
||||||
|
@ -86,18 +88,26 @@ public class AuditEventListener implements PostInsertEventListener, PostUpdateEv
|
||||||
Object newValue = newState == null ? null : newState[i];
|
Object newValue = newState == null ? null : newState[i];
|
||||||
|
|
||||||
if (!Tools.objectsEqual(oldValue, newValue)) {
|
if (!Tools.objectsEqual(oldValue, newValue)) {
|
||||||
IdMapper idMapper = verCfg.getEntCfg().get(relDesc.getToEntityName()).getIdMapper();
|
|
||||||
|
|
||||||
// We have to generate changes both in the old collection (size decreses) and new collection
|
// We have to generate changes both in the old collection (size decreses) and new collection
|
||||||
// (size increases).
|
// (size increases).
|
||||||
if (newValue != null) {
|
if (newValue != null) {
|
||||||
|
// relDesc.getToEntityName() doesn't always return the entity name of the value - in case
|
||||||
|
// of subclasses, this will be root class, no the actual class. So it can't be used here.
|
||||||
|
String toEntityName = session.guessEntityName(newValue);
|
||||||
|
|
||||||
|
IdMapper idMapper = verCfg.getEntCfg().get(toEntityName).getIdMapper();
|
||||||
|
|
||||||
Serializable id = (Serializable) idMapper.mapToIdFromEntity(newValue);
|
Serializable id = (Serializable) idMapper.mapToIdFromEntity(newValue);
|
||||||
verSync.addWorkUnit(new CollectionChangeWorkUnit(relDesc.getToEntityName(), verCfg, id, newValue));
|
verSync.addWorkUnit(new CollectionChangeWorkUnit(toEntityName, verCfg, id, newValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldValue != null) {
|
if (oldValue != null) {
|
||||||
|
String toEntityName = session.guessEntityName(oldValue);
|
||||||
|
|
||||||
|
IdMapper idMapper = verCfg.getEntCfg().get(toEntityName).getIdMapper();
|
||||||
|
|
||||||
Serializable id = (Serializable) idMapper.mapToIdFromEntity(oldValue);
|
Serializable id = (Serializable) idMapper.mapToIdFromEntity(oldValue);
|
||||||
verSync.addWorkUnit(new CollectionChangeWorkUnit(relDesc.getToEntityName(), verCfg, id, oldValue));
|
verSync.addWorkUnit(new CollectionChangeWorkUnit(toEntityName, verCfg, id, oldValue));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,7 +123,8 @@ public class AuditEventListener implements PostInsertEventListener, PostUpdateEv
|
||||||
verSync.addWorkUnit(new AddWorkUnit(event.getPersister().getEntityName(), verCfg, event.getId(),
|
verSync.addWorkUnit(new AddWorkUnit(event.getPersister().getEntityName(), verCfg, event.getId(),
|
||||||
event.getPersister(), event.getState()));
|
event.getPersister(), event.getState()));
|
||||||
|
|
||||||
generateBidirectionalCollectionChangeWorkUnits(verSync, event.getPersister(), entityName, event.getState(), null);
|
generateBidirectionalCollectionChangeWorkUnits(verSync, event.getPersister(), entityName, event.getState(),
|
||||||
|
null, event.getSession());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,7 +137,8 @@ public class AuditEventListener implements PostInsertEventListener, PostUpdateEv
|
||||||
verSync.addWorkUnit(new ModWorkUnit(event.getPersister().getEntityName(), verCfg, event.getId(),
|
verSync.addWorkUnit(new ModWorkUnit(event.getPersister().getEntityName(), verCfg, event.getId(),
|
||||||
event.getPersister(), event.getState(), event.getOldState()));
|
event.getPersister(), event.getState(), event.getOldState()));
|
||||||
|
|
||||||
generateBidirectionalCollectionChangeWorkUnits(verSync, event.getPersister(), entityName, event.getState(), event.getOldState());
|
generateBidirectionalCollectionChangeWorkUnits(verSync, event.getPersister(), entityName, event.getState(),
|
||||||
|
event.getOldState(), event.getSession());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,7 +150,8 @@ public class AuditEventListener implements PostInsertEventListener, PostUpdateEv
|
||||||
|
|
||||||
verSync.addWorkUnit(new DelWorkUnit(event.getPersister().getEntityName(), verCfg, event.getId()));
|
verSync.addWorkUnit(new DelWorkUnit(event.getPersister().getEntityName(), verCfg, event.getId()));
|
||||||
|
|
||||||
generateBidirectionalCollectionChangeWorkUnits(verSync, event.getPersister(), entityName, null, event.getDeletedState());
|
generateBidirectionalCollectionChangeWorkUnits(verSync, event.getPersister(), entityName, null,
|
||||||
|
event.getDeletedState(), event.getSession());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
package org.hibernate.envers.test.integration.inheritance.single.inheritedrelation;
|
||||||
|
|
||||||
|
import org.hibernate.envers.Audited;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Audited
|
||||||
|
public class Address implements Serializable {
|
||||||
|
@Id @GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String address1;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
private Contact contact;
|
||||||
|
|
||||||
|
public Address() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Address(Long id, String address1) {
|
||||||
|
this.id = id;
|
||||||
|
this.address1 = address1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAddress1() {
|
||||||
|
return address1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddress1(String address1) {
|
||||||
|
this.address1 = address1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Contact getContact() {
|
||||||
|
return contact;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContact(Contact contact) {
|
||||||
|
this.contact = contact;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (!(o instanceof Address)) return false;
|
||||||
|
|
||||||
|
Address address = (Address) o;
|
||||||
|
|
||||||
|
if (address1 != null ? !address1.equals(address.address1) : address.address1 != null) return false;
|
||||||
|
if (id != null ? !id.equals(address.id) : address.id != null) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
int result;
|
||||||
|
result = (id != null ? id.hashCode() : 0);
|
||||||
|
result = 31 * result + (address1 != null ? address1.hashCode() : 0);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package org.hibernate.envers.test.integration.inheritance.single.inheritedrelation;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.persistence.DiscriminatorColumn;
|
||||||
|
import javax.persistence.DiscriminatorValue;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Inheritance;
|
||||||
|
import javax.persistence.InheritanceType;
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
|
|
||||||
|
import org.hibernate.envers.Audited;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
|
||||||
|
@DiscriminatorValue("Contact")
|
||||||
|
@DiscriminatorColumn(name="contactType",discriminatorType=javax.persistence.DiscriminatorType.STRING)
|
||||||
|
@Audited
|
||||||
|
public class Contact implements Serializable {
|
||||||
|
@Id @GeneratedValue
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy="contact")
|
||||||
|
private Set<Address> addresses;
|
||||||
|
|
||||||
|
public Contact() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
public void setId(Long id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Address> getAddresses() {
|
||||||
|
return addresses;
|
||||||
|
}
|
||||||
|
public void setAddresses(Set<Address> addresses) {
|
||||||
|
this.addresses = addresses;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,120 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat Middleware LLC.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.hibernate.envers.test.integration.inheritance.single.inheritedrelation;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
|
||||||
|
import org.hibernate.envers.test.AbstractEntityTest;
|
||||||
|
import org.hibernate.envers.test.tools.TestTools;
|
||||||
|
import org.testng.annotations.BeforeClass;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import org.hibernate.ejb.Ejb3Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Adam Warski (adam at warski dot org)
|
||||||
|
*/
|
||||||
|
public class InheritedBidirectional extends AbstractEntityTest {
|
||||||
|
private Long pc_id;
|
||||||
|
private Long a1_id;
|
||||||
|
private Long a2_id;
|
||||||
|
|
||||||
|
public void configure(Ejb3Configuration cfg) {
|
||||||
|
cfg.addAnnotatedClass(Address.class);
|
||||||
|
cfg.addAnnotatedClass(Contact.class);
|
||||||
|
cfg.addAnnotatedClass(PersonalContact.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass(dependsOnMethods = "init")
|
||||||
|
public void initData() {
|
||||||
|
EntityManager em = getEntityManager();
|
||||||
|
|
||||||
|
// Rev 1
|
||||||
|
em.getTransaction().begin();
|
||||||
|
|
||||||
|
PersonalContact pc = new PersonalContact();
|
||||||
|
pc.setEmail("e");
|
||||||
|
pc.setFirstname("f");
|
||||||
|
|
||||||
|
Address a1 = new Address();
|
||||||
|
a1.setAddress1("a1");
|
||||||
|
a1.setContact(pc);
|
||||||
|
|
||||||
|
em.persist(pc);
|
||||||
|
em.persist(a1);
|
||||||
|
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
// Rev 2
|
||||||
|
em.getTransaction().begin();
|
||||||
|
|
||||||
|
pc = em.find(PersonalContact.class, pc.getId());
|
||||||
|
|
||||||
|
Address a2 = new Address();
|
||||||
|
a2.setAddress1("a2");
|
||||||
|
a2.setContact(pc);
|
||||||
|
|
||||||
|
em.persist(a2);
|
||||||
|
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
pc_id = pc.getId();
|
||||||
|
a1_id = a1.getId();
|
||||||
|
a2_id = a2.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRevisionsCounts() {
|
||||||
|
assert Arrays.asList(1, 2).equals(getAuditReader().getRevisions(Contact.class, pc_id));
|
||||||
|
assert Arrays.asList(1, 2).equals(getAuditReader().getRevisions(PersonalContact.class, pc_id));
|
||||||
|
|
||||||
|
assert Arrays.asList(1).equals(getAuditReader().getRevisions(Address.class, a1_id));
|
||||||
|
assert Arrays.asList(1).equals(getAuditReader().getRevisions(Address.class, a1_id));
|
||||||
|
|
||||||
|
assert Arrays.asList(2).equals(getAuditReader().getRevisions(Address.class, a2_id));
|
||||||
|
assert Arrays.asList(2).equals(getAuditReader().getRevisions(Address.class, a2_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHistoryOfContact() {
|
||||||
|
assert getAuditReader().find(Contact.class, pc_id, 1).getAddresses().equals(
|
||||||
|
TestTools.makeSet(new Address(a1_id, "a1")));
|
||||||
|
|
||||||
|
assert getAuditReader().find(Contact.class, pc_id, 2).getAddresses().equals(
|
||||||
|
TestTools.makeSet(new Address(a1_id, "a1"), new Address(a2_id, "a2")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHistoryOfPersonalContact() {
|
||||||
|
assert getAuditReader().find(PersonalContact.class, pc_id, 1).getAddresses().equals(
|
||||||
|
TestTools.makeSet(new Address(a1_id, "a1")));
|
||||||
|
|
||||||
|
assert getAuditReader().find(PersonalContact.class, pc_id, 2).getAddresses().equals(
|
||||||
|
TestTools.makeSet(new Address(a1_id, "a1"), new Address(a2_id, "a2")));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package org.hibernate.envers.test.integration.inheritance.single.inheritedrelation;
|
||||||
|
|
||||||
|
import javax.persistence.DiscriminatorValue;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
|
||||||
|
import org.hibernate.envers.Audited;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@DiscriminatorValue("PersonalContact")
|
||||||
|
@Audited
|
||||||
|
public class PersonalContact extends Contact {
|
||||||
|
private String firstname;
|
||||||
|
|
||||||
|
public String getFirstname() {
|
||||||
|
return firstname;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFirstname(String firstname) {
|
||||||
|
this.firstname = firstname;
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,6 +15,7 @@
|
||||||
<package name="org.hibernate.envers.test.integration.ids" />
|
<package name="org.hibernate.envers.test.integration.ids" />
|
||||||
<package name="org.hibernate.envers.test.integration.inheritance.single" />
|
<package name="org.hibernate.envers.test.integration.inheritance.single" />
|
||||||
<package name="org.hibernate.envers.test.integration.inheritance.single.childrelation" />
|
<package name="org.hibernate.envers.test.integration.inheritance.single.childrelation" />
|
||||||
|
<package name="org.hibernate.envers.test.integration.inheritance.single.inheritedrelation" />
|
||||||
<package name="org.hibernate.envers.test.integration.inheritance.single.relation" />
|
<package name="org.hibernate.envers.test.integration.inheritance.single.relation" />
|
||||||
<package name="org.hibernate.envers.test.integration.manytomany" />
|
<package name="org.hibernate.envers.test.integration.manytomany" />
|
||||||
<package name="org.hibernate.envers.test.integration.manytomany.ternary" />
|
<package name="org.hibernate.envers.test.integration.manytomany.ternary" />
|
||||||
|
|
Loading…
Reference in New Issue