Подтвердить что ты не робот

Hibernate Envers: @Аудируется в подклассе

У меня есть классическое наследование наследования с сущностями Parent и Child, где Child extends Parent. Класс Родитель является абстрактным, а Ребенок - нет.

Я хочу проверить Child. Этот объект находится под моим контролем, а Parent - нет. Кроме того, у него есть много других подклассов, которые не нужно проверять. Стратегия наследования для всей иерархии СОЕДИНЕНА.

Итак, я аннотировал Child с @Audited и дополнительно с @AuditOverride (forclass= Parent.class).

Я получаю эту ошибку:

"org.hibernate.MappingException: сущность" Child "проверяется, но его суперкласс:" Родитель "- нет."

Кстати, я использую envers 4.0.1.Final version.

Кто-нибудь знает, как я могу это достичь? Я попытался удалить @Audited в классе Child, удалив @AuditOverride, используя устаревшие параметры аудита в @Audited аннотации, но ничего не работает.

Это родительский объект:

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

}

И, наконец, здесь картофель:

Картофельное изображение

Заранее благодарю вас!

4b9b3361

Ответ 1

Очень хороший вопрос. Было такое же обсуждение на форуме разработчиков jboss в 2013 году. И ответ был от основателя и руководителя проекта Hibernate Enver:

Вам нужно было бы заставить суперкласс провести аудит каким-то образом. В данный момент нет другого способа указать такие метаданные, кроме аннотаций.

В том же дереве обсуждения, в соответствии с тем, что родительский класс также должен быть аннотирован, было предложено аннотировать их во время выполнения. Но это решение кажется уродливым и не подходит в вашем случае: вы можете вручную аннотировать родительский класс.

В качестве обходного пути, если вы не хотите, чтобы проверялся родительский класс, вы можете попробовать создать базовый реферат MappedSuperClass, который по существу будет таким же, как Parent, а Parent будет только его потомком, а затем попробуйте @AuditOverride снова для класса Child. Возможно, что он "пропустит" аудит для класса Parent и сделает это для Child.