HHH-4073 - Discriminator formula support in Envers

This commit is contained in:
Lukasz Antoniak 2011-04-13 19:12:44 +02:00
parent dfcdab4a33
commit 40f28ff69c
6 changed files with 384 additions and 4 deletions

View File

@ -64,6 +64,7 @@ import org.jboss.logging.Logger;
* @author Tomasz Bech
* @author Stephanie Pau at Markit Group Plc
* @author Hernán Chanfreau
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public final class AuditMetadataGenerator {
@ -331,7 +332,8 @@ public final class AuditMetadataGenerator {
// Checking if there is a discriminator column
if (pc.getDiscriminator() != null) {
Element discriminator_element = class_mapping.addElement("discriminator");
MetadataTools.addColumns(discriminator_element, pc.getDiscriminator().getColumnIterator());
// Database column or SQL formula allowed to distinguish entity types
MetadataTools.addColumnsOrFormulas(discriminator_element, pc.getDiscriminator().getColumnIterator());
discriminator_element.addAttribute("type", pc.getDiscriminator().getType().getName());
}

View File

@ -29,9 +29,11 @@ import org.dom4j.Document;
import org.dom4j.Element;
import org.hibernate.envers.tools.StringTools;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Formula;
/**
* @author Adam Warski (adam at warski dot org)
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class MetadataTools {
public static Element addNativelyGeneratedId(Element parent, String name, String type) {
@ -182,11 +184,21 @@ public class MetadataTools {
public static void addColumns(Element any_mapping, Iterator<Column> columns) {
while (columns.hasNext()) {
Column column = columns.next();
addColumn(any_mapping, columns.next());
}
}
/**
* Adds <code>column</code> element with the following attributes (unless empty): <code>name</code>,
* <code>length</code>, <code>scale</code>, <code>precision</code>, <code>sql-type</code>, <code>read</code>
* and <code>write</code>.
* @param any_mapping Parent element.
* @param column Column descriptor.
*/
public static void addColumn(Element any_mapping, Column column) {
addColumn(any_mapping, column.getName(), column.getLength(), column.getScale(), column.getPrecision(),
column.getSqlType(), column.getCustomRead(), column.getCustomWrite());
}
}
@SuppressWarnings({"unchecked"})
private static void changeNamesInColumnElement(Element element, ColumnNameIterator columnNameIterator) {
@ -228,6 +240,32 @@ public class MetadataTools {
}
}
/**
* Adds <code>formula</code> element.
* @param element Parent element.
* @param formula Formula descriptor.
*/
public static void addFormula(Element element, Formula formula) {
element.addElement("formula").setText(formula.getText());
}
/**
* Adds all <code>column</code> or <code>formula</code> elements.
* @param element Parent element.
* @param columnIterator Iterator pointing at {@link org.hibernate.mapping.Column} and/or
* {@link org.hibernate.mapping.Formula} objects.
*/
public static void addColumnsOrFormulas(Element element, Iterator columnIterator) {
while (columnIterator.hasNext()) {
Object o = columnIterator.next();
if (o instanceof Column) {
addColumn(element, (Column) o);
} else if (o instanceof Formula) {
addFormula(element, (Formula) o);
}
}
}
/**
* An iterator over column names.
*/

View File

@ -0,0 +1,59 @@
package org.hibernate.envers.test.integration.inheritance.single.discriminatorformula;
import org.hibernate.envers.Audited;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@Entity
@DiscriminatorValue(ClassTypeEntity.CHILD_TYPE)
@Audited
public class ChildEntity extends ParentEntity {
private String specificData;
public ChildEntity() {
}
public ChildEntity(Long typeId, String data, String specificData) {
super(typeId, data);
this.specificData = specificData;
}
public ChildEntity(Long id, Long typeId, String data, String specificData) {
super(id, typeId, data);
this.specificData = specificData;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ChildEntity)) return false;
if (!super.equals(o)) return false;
ChildEntity that = (ChildEntity) o;
if (specificData != null ? !specificData.equals(that.specificData) : that.specificData != null) return false;
return true;
}
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (specificData != null ? specificData.hashCode() : 0);
return result;
}
public String toString() {
return "ChildEntity(id = " + id + ", typeId = " + typeId + ", data = " + data + ", specificData = " + specificData + ")";
}
public String getSpecificData() {
return specificData;
}
public void setSpecificData(String specificData) {
this.specificData = specificData;
}
}

View File

@ -0,0 +1,59 @@
package org.hibernate.envers.test.integration.inheritance.single.discriminatorformula;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@Entity
public class ClassTypeEntity {
public static final String PARENT_TYPE = "Parent";
public static final String CHILD_TYPE = "Child";
@Id
@GeneratedValue
private Long id;
private String type;
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ClassTypeEntity)) return false;
ClassTypeEntity that = (ClassTypeEntity) o;
if (id != null ? !id.equals(that.id) : that.id != null) return false;
if (type != null ? !type.equals(that.type) : that.type != null) return false;
return true;
}
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (id != null ? id.hashCode() : 0);
result = 31 * result + (type != null ? type.hashCode() : 0);
return result;
}
public String toString() {
return "ClassTypeEntity(id = " + id + ", type = " + type + ")";
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}

View File

@ -0,0 +1,131 @@
package org.hibernate.envers.test.integration.inheritance.single.discriminatorformula;
import org.hibernate.ejb.Ejb3Configuration;
import org.hibernate.envers.test.AbstractEntityTest;
import org.hibernate.envers.test.Priority;
import org.hibernate.mapping.Formula;
import org.hibernate.mapping.PersistentClass;
import org.junit.Test;
import javax.persistence.EntityManager;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
public class DiscriminatorFormulaTest extends AbstractEntityTest {
private PersistentClass parentAudit = null;
private ChildEntity childVer1 = null;
private ChildEntity childVer2 = null;
private ParentEntity parentVer1 = null;
private ParentEntity parentVer2 = null;
@Override
public void configure(Ejb3Configuration cfg) {
cfg.addAnnotatedClass(ClassTypeEntity.class);
cfg.addAnnotatedClass(ParentEntity.class);
cfg.addAnnotatedClass(ChildEntity.class);
}
@Test
@Priority(10)
public void initData() {
parentAudit = getCfg().getClassMapping("org.hibernate.envers.test.integration.inheritance.single.discriminatorformula.ParentEntity_AUD");
EntityManager em = getEntityManager();
// Child entity type
em.getTransaction().begin();
ClassTypeEntity childType = new ClassTypeEntity();
childType.setType(ClassTypeEntity.CHILD_TYPE);
em.persist(childType);
Long childTypeId = childType.getId();
em.getTransaction().commit();
// Parent entity type
em.getTransaction().begin();
ClassTypeEntity parentType = new ClassTypeEntity();
parentType.setType(ClassTypeEntity.PARENT_TYPE);
em.persist(parentType);
Long parentTypeId = parentType.getId();
em.getTransaction().commit();
// Child Rev 1
em.getTransaction().begin();
ChildEntity child = new ChildEntity(childTypeId, "Child data", "Child specific data");
em.persist(child);
Long childId = child.getId();
em.getTransaction().commit();
// Parent Rev 2
em.getTransaction().begin();
ParentEntity parent = new ParentEntity(parentTypeId, "Parent data");
em.persist(parent);
Long parentId = parent.getId();
em.getTransaction().commit();
// Child Rev 3
em.getTransaction().begin();
child = em.find(ChildEntity.class, childId);
child.setData("Child data modified");
em.getTransaction().commit();
// Parent Rev 4
em.getTransaction().begin();
parent = em.find(ParentEntity.class, parentId);
parent.setData("Parent data modified");
em.getTransaction().commit();
childVer1 = new ChildEntity(childId, childTypeId, "Child data", "Child specific data");
childVer2 = new ChildEntity(childId, childTypeId, "Child data modified", "Child specific data");
parentVer1 = new ParentEntity(parentId, parentTypeId, "Parent data");
parentVer2 = new ParentEntity(parentId, parentTypeId, "Parent data modified");
}
@Test
public void testDiscriminatorFormulaInAuditTable() {
assert parentAudit.getDiscriminator().hasFormula();
Iterator iterator = parentAudit.getDiscriminator().getColumnIterator();
while (iterator.hasNext()) {
Object o = iterator.next();
if (o instanceof Formula) {
Formula formula = (Formula) o;
assert formula.getText().equals(ParentEntity.DISCRIMINATOR_QUERY);
return;
}
}
assert false;
}
@Test
public void testRevisionsCounts() {
assert Arrays.asList(1, 3).equals(getAuditReader().getRevisions(ChildEntity.class, childVer1.getId()));
assert Arrays.asList(2, 4).equals(getAuditReader().getRevisions(ParentEntity.class, parentVer1.getId()));
}
@Test
public void testHistoryOfParent() {
assert getAuditReader().find(ParentEntity.class, parentVer1.getId(), 2).equals(parentVer1);
assert getAuditReader().find(ParentEntity.class, parentVer2.getId(), 4).equals(parentVer2);
}
@Test
public void testHistoryOfChild() {
assert getAuditReader().find(ChildEntity.class, childVer1.getId(), 1).equals(childVer1);
assert getAuditReader().find(ChildEntity.class, childVer2.getId(), 3).equals(childVer2);
}
@Test
public void testPolymorphicQuery() {
assert getAuditReader().createQuery().forEntitiesAtRevision(ChildEntity.class, 1).getSingleResult().equals(childVer1);
assert getAuditReader().createQuery().forEntitiesAtRevision(ParentEntity.class, 1).getSingleResult().equals(childVer1);
List childEntityRevisions = getAuditReader().createQuery().forRevisionsOfEntity(ChildEntity.class, true, false).getResultList();
assert Arrays.asList(childVer1, childVer2).equals(childEntityRevisions);
List parentEntityRevisions = getAuditReader().createQuery().forRevisionsOfEntity(ParentEntity.class, true, false).getResultList();
assert Arrays.asList(childVer1, parentVer1, childVer2, parentVer2).equals(parentEntityRevisions);
}
}

View File

@ -0,0 +1,91 @@
package org.hibernate.envers.test.integration.inheritance.single.discriminatorformula;
import org.hibernate.annotations.DiscriminatorFormula;
import org.hibernate.envers.Audited;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
/**
* @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com)
*/
@Entity
@DiscriminatorFormula(ParentEntity.DISCRIMINATOR_QUERY)
@DiscriminatorValue(ClassTypeEntity.PARENT_TYPE)
@Audited
public class ParentEntity {
public static final String DISCRIMINATOR_QUERY = "(SELECT c.type FROM ClassTypeEntity c WHERE c.id = typeId)";
@Id
@GeneratedValue
protected Long id;
protected Long typeId;
protected String data;
public ParentEntity() {
}
public ParentEntity(Long typeId, String data) {
this.typeId = typeId;
this.data = data;
}
public ParentEntity(Long id, Long typeId, String data) {
this.id = id;
this.typeId = typeId;
this.data = data;
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ParentEntity)) return false;
ParentEntity that = (ParentEntity) o;
if (id != null ? !id.equals(that.id) : that.id != null) return false;
if (typeId != null ? !typeId.equals(that.id) : that.typeId != null) return false;
if (data != null ? !data.equals(that.data) : that.data != null) return false;
return true;
}
public int hashCode() {
int result;
result = (id != null ? id.hashCode() : 0);
result = 31 * result + (typeId != null ? typeId.hashCode() : 0);
result = 31 * result + (data != null ? data.hashCode() : 0);
return result;
}
public String toString() {
return "ParentEntity(id = " + id + ", typeId = " + typeId + ", data = " + data + ")";
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getTypeId() {
return typeId;
}
public void setTypeId(Long typeId) {
this.typeId = typeId;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}