Hibernate Envers:@Audited 子类
Hibernate Envers: @Audited on a subclass
我有实体 Parent 和 Child 的 classic 继承持久性,其中 Child 扩展 父级 。 Class Parent 是抽象的,而 Child 不是。
我想审计子。这个实体在我的控制之下,而父不是。此外,它还有许多其他子class项不需要审计。整个层级的继承策略是JOINED.
所以我用 @Audited 和 @AuditOverride(forClass 注释了 Child = Parent.class).
我得到的是这个错误:
"org.hibernate.MappingException: Entity 'Child' is audited, but its superclass: 'Parent' is not."
对了,我用的是envers 4.0.1.Final版本。
有人知道我该怎么做吗?
我试过在 Child class 中删除 @Audited,删除 @AuditOverride,使用在 @Audited 注释中弃用了 auditParents,但似乎没有任何效果。
这是父实体:
@Entity
@Table(name = "parent")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "type")
public class Parent {
public Parent() {
super();
}
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "base_id", unique = true, nullable = false)
private Integer baseId;
@Column(name = "base_field")
private String baseField;
@Column(name = "type")
private String type;
// getters and setters
}
这是我的子实体:
@Entity
@Table(name = "child")
@DiscriminatorValue("CHILD")
@Audited
@AuditOverride(forClass = Parent.class)
public class Child extends Parent {
public Child() {
super();
}
@Column(name = "child_field")
private String childField;
// getters and setters
}
这是实体:
CREATE TABLE `REVINFO` (
`REV` BIGINT NOT NULL AUTO_INCREMENT,
`REVTSTMP` BIGINT NULL ,
PRIMARY KEY (`REV`)
);
CREATE TABLE `parent` (
`base_id` int(11) NOT NULL AUTO_INCREMENT,
`base_field` varchar(45) DEFAULT NULL,
`type` varchar(45) NOT NULL,
PRIMARY KEY (`base_id`)
);
CREATE TABLE `child` (
`base_id` int(11) NOT NULL AUTO_INCREMENT,
`child_field` varchar(45) DEFAULT NULL,
PRIMARY KEY (`base_id`)
);
CREATE TABLE `child_AUD` (
`base_id` int(11) NOT NULL,
`REV` BIGINT NOT NULL,
`REVTYPE` tinyint(2) DEFAULT NULL,
`child_field` varchar(45) DEFAULT NULL,
PRIMARY KEY (`base_id`,`REV`)
);
这是一个测试用例:
public class EnversInheritanceTest extends AbstractJUnit4SpringContextTests {
@Inject
private EntityManagerFactory entityManagerFactory;
private EntityManager entityManager;
@Test
public void inheritanceTest() {
this.entityManager = this.entityManagerFactory.createEntityManager();
Child child = this.createChild();
this.saveChild(child);
this.modifyChild(child);
this.saveChild(child);
Assert.assertNotNull(child.getBaseId());
Assert.assertNotNull(this.getOriginalRevision(child.getBaseId()));
Child original = this.getOriginalChild(child.getBaseId());
Assert.assertNotNull(original);
Assert.assertEquals("child", original.getChildField());
}
private Child createChild() {
Child child = new Child();
child.setBaseField("base");
child.setChildField("child");
child.setType("CHILD");
return child;
}
private void saveChild(Child child) {
this.entityManager.getTransaction().begin();
this.entityManager.persist(child);
// We need to commit in order to trigger Envers magic
this.entityManager.getTransaction().commit();
}
private void modifyChild(Child child) {
child.setBaseField("foo");
child.setChildField("bar");
}
public Child getOriginalChild(Serializable id) {
Object queryResult = this.getAuditReader().createQuery()
.forEntitiesAtRevision(Child.class, this.getOriginalRevision(id))
.add(AuditEntity.id().eq(id))
.getSingleResult();
return (Child) queryResult;
}
private Number getOriginalRevision(Serializable id) {
AuditProjection minRevNumberAuditProjection = AuditEntity.revisionNumber().min();
Number revision = (Number) this.getAuditReader().createQuery()
.forRevisionsOfEntity(Child.class, false, false)
.add(AuditEntity.id().eq(id))
.addProjection(minRevNumberAuditProjection)
.getSingleResult();
return revision;
}
private AuditReader getAuditReader() {
return AuditReaderFactory.get(this.entityManager);
}
}
提前致谢!
一个很好的问题。有 same discussion on the jboss
developers forum in 2013 year. And the answer was from the founder and project lead of Hibernate Enver:
You would have to get the superclass audited somehow. Currently
there's no other way to specify such metadata except for annotations.
在同一个讨论树中,根据父class也应该被注释的事实,建议在运行时注释它们。但是这个决定似乎很难看并且不适合你的情况:你可以手动注释父 class。
作为变通方法,如果您不希望父 class 被审计,您可以尝试创建一个基本摘要 MappedSuperClass
,它基本上与 Parent
相同,而 Parent
将只是它的后代,然后尝试为 Child
class 再次放置 @AuditOverride
。它可能会 "skip" 审核 Parent
class 并为 Child
.
审核
尝试用@Audited注解标记父子classes
但对于父 class 添加 @Audited(targetAuditMode = NOT_AUDITED)
我有实体 Parent 和 Child 的 classic 继承持久性,其中 Child 扩展 父级 。 Class Parent 是抽象的,而 Child 不是。
我想审计子。这个实体在我的控制之下,而父不是。此外,它还有许多其他子class项不需要审计。整个层级的继承策略是JOINED.
所以我用 @Audited 和 @AuditOverride(forClass 注释了 Child = Parent.class).
我得到的是这个错误:
"org.hibernate.MappingException: Entity 'Child' is audited, but its superclass: 'Parent' is not."
对了,我用的是envers 4.0.1.Final版本。
有人知道我该怎么做吗? 我试过在 Child class 中删除 @Audited,删除 @AuditOverride,使用在 @Audited 注释中弃用了 auditParents,但似乎没有任何效果。
这是父实体:
@Entity
@Table(name = "parent")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "type")
public class Parent {
public Parent() {
super();
}
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "base_id", unique = true, nullable = false)
private Integer baseId;
@Column(name = "base_field")
private String baseField;
@Column(name = "type")
private String type;
// getters and setters
}
这是我的子实体:
@Entity
@Table(name = "child")
@DiscriminatorValue("CHILD")
@Audited
@AuditOverride(forClass = Parent.class)
public class Child extends Parent {
public Child() {
super();
}
@Column(name = "child_field")
private String childField;
// getters and setters
}
这是实体:
CREATE TABLE `REVINFO` (
`REV` BIGINT NOT NULL AUTO_INCREMENT,
`REVTSTMP` BIGINT NULL ,
PRIMARY KEY (`REV`)
);
CREATE TABLE `parent` (
`base_id` int(11) NOT NULL AUTO_INCREMENT,
`base_field` varchar(45) DEFAULT NULL,
`type` varchar(45) NOT NULL,
PRIMARY KEY (`base_id`)
);
CREATE TABLE `child` (
`base_id` int(11) NOT NULL AUTO_INCREMENT,
`child_field` varchar(45) DEFAULT NULL,
PRIMARY KEY (`base_id`)
);
CREATE TABLE `child_AUD` (
`base_id` int(11) NOT NULL,
`REV` BIGINT NOT NULL,
`REVTYPE` tinyint(2) DEFAULT NULL,
`child_field` varchar(45) DEFAULT NULL,
PRIMARY KEY (`base_id`,`REV`)
);
这是一个测试用例:
public class EnversInheritanceTest extends AbstractJUnit4SpringContextTests {
@Inject
private EntityManagerFactory entityManagerFactory;
private EntityManager entityManager;
@Test
public void inheritanceTest() {
this.entityManager = this.entityManagerFactory.createEntityManager();
Child child = this.createChild();
this.saveChild(child);
this.modifyChild(child);
this.saveChild(child);
Assert.assertNotNull(child.getBaseId());
Assert.assertNotNull(this.getOriginalRevision(child.getBaseId()));
Child original = this.getOriginalChild(child.getBaseId());
Assert.assertNotNull(original);
Assert.assertEquals("child", original.getChildField());
}
private Child createChild() {
Child child = new Child();
child.setBaseField("base");
child.setChildField("child");
child.setType("CHILD");
return child;
}
private void saveChild(Child child) {
this.entityManager.getTransaction().begin();
this.entityManager.persist(child);
// We need to commit in order to trigger Envers magic
this.entityManager.getTransaction().commit();
}
private void modifyChild(Child child) {
child.setBaseField("foo");
child.setChildField("bar");
}
public Child getOriginalChild(Serializable id) {
Object queryResult = this.getAuditReader().createQuery()
.forEntitiesAtRevision(Child.class, this.getOriginalRevision(id))
.add(AuditEntity.id().eq(id))
.getSingleResult();
return (Child) queryResult;
}
private Number getOriginalRevision(Serializable id) {
AuditProjection minRevNumberAuditProjection = AuditEntity.revisionNumber().min();
Number revision = (Number) this.getAuditReader().createQuery()
.forRevisionsOfEntity(Child.class, false, false)
.add(AuditEntity.id().eq(id))
.addProjection(minRevNumberAuditProjection)
.getSingleResult();
return revision;
}
private AuditReader getAuditReader() {
return AuditReaderFactory.get(this.entityManager);
}
}
提前致谢!
一个很好的问题。有 same discussion on the jboss
developers forum in 2013 year. And the answer was from the founder and project lead of Hibernate Enver:
You would have to get the superclass audited somehow. Currently there's no other way to specify such metadata except for annotations.
在同一个讨论树中,根据父class也应该被注释的事实,建议在运行时注释它们。但是这个决定似乎很难看并且不适合你的情况:你可以手动注释父 class。
作为变通方法,如果您不希望父 class 被审计,您可以尝试创建一个基本摘要 MappedSuperClass
,它基本上与 Parent
相同,而 Parent
将只是它的后代,然后尝试为 Child
class 再次放置 @AuditOverride
。它可能会 "skip" 审核 Parent
class 并为 Child
.
尝试用@Audited注解标记父子classes 但对于父 class 添加 @Audited(targetAuditMode = NOT_AUDITED)