Возникли трудности с использованием Envers для аудита отношения многих ко многим - PullRequest
1 голос
/ 02 февраля 2012

Я хочу использовать Envers для аудита связи «многие ко многим» со встроенным компонентом, но у меня возникли проблемы с MappingException, говорящим, что ComponentType не поддерживается.Это релевантная часть трассировки стека:

Caused by: org.hibernate.MappingException: Type not supported: org.hibernate.type.ComponentType
        at org.hibernate.envers.configuration.metadata.IdMetadataGenerator.addIdProperties(IdMetadataGenerator.java:74)
        at org.hibernate.envers.configuration.metadata.IdMetadataGenerator.addId(IdMetadataGenerator.java:105)
        at org.hibernate.envers.configuration.metadata.AuditMetadataGenerator.generateFirstPass(AuditMetadataGenerator.java:413)
        at org.hibernate.envers.configuration.EntitiesConfigurator.configure(EntitiesConfigurator.java:101)
        at org.hibernate.envers.configuration.AuditConfiguration.<init>(AuditConfiguration.java:103)
        at org.hibernate.envers.configuration.AuditConfiguration.getFor(AuditConfiguration.java:135)
        at org.hibernate.envers.event.EnversIntegrator.integrate(EnversIntegrator.java:63)
        at org.hibernate.internal.SessionFactoryImpl.<init>(SessionFactoryImpl.java:295)
        at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1737)
        at org.hibernate.ejb.EntityManagerFactoryImpl.<init>(EntityManagerFactoryImpl.java:76)
        at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:905)

При чтении ссылки Envers выясняется, что Envers может справиться с тем, что я пытаюсь сделать.Согласно ссылке:

Если вы хотите переопределить поведение аудита некоторых полей / свойств, унаследованных от @Mappedsuperclass или во встроенном компоненте, вы можете применить аннотацию @AuditOverride (s) кподтип или сайт использования компонента.

Вот моя ассоциативная сущность.Вы можете увидеть, где я пытался использовать @AuditOverride на уровне класса, чтобы предотвратить аудит встроенного компонента.Я также попытался использовать аннотацию на самом поле.Ни один не сделал разницу.

@Audited
//  @AuditOverride(name = "pk", isAudited = false) <===== Didn't help
@Table(name = "user_role")
@javax.persistence.Entity
@AssociationOverrides
(
    {
    @AssociationOverride
        (name = "pk.user", joinColumns = @JoinColumn(name = "id")),
    @AssociationOverride
        (name = "pk.role", joinColumns = @JoinColumn(name = "id"))
    }
)
public class UserRole extends Entity<UserRole>
{
    private static final long serialVersionUID = 1L;

    private Date expirationDate;
    private UserRolePk pk = new UserRolePk();

    public UserRole() {}

    //  @AuditOverride(name = "pk", isAudited = false) <== Didn't help
    @EmbeddedId
    public UserRolePk getPk() { return pk; }

    @Transient
    public User getUser() { return getPk().getUser(); }

    @Transient
    public Role getRole() { return getPk().getRole(); }
...
}

Вот сущность пользователя:

@Audited
@Table(name = "applicationuser")
@javax.persistence.Entity
public class User extends Entity<User>
{
    private static final long serialVersionUID = 1L;
    private String firstName;
    private String lastName;
    private String email;
    private Set<UserRole> userRoles = new HashSet<UserRole>(0);

    @OneToMany(fetch = FetchType.LAZY, cascade=CascadeType.ALL,
        mappedBy = "pk.user", orphanRemoval = true)

    public Set<UserRole> getUserRoles() { return userRoles; }
...
}

Вот сущность роли:

@Audited
@Table(name = "role")
@javax.persistence.Entity
public class Role extends Entity<Role>
{
    private static final long serialVersionUID = 1L;
    private String name;
    private String label;
    private Set<UserRole> userRoles = new HashSet<UserRole>(0);

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.role",
        cascade=CascadeType.ALL, orphanRemoval = true)

    public Set<UserRole> getUserRoles() { return userRoles; }
...
}

Вот встроенный компонент:

@Embeddable
public class UserRolePk implements Serializable
{
    private static final long serialVersionUID = 1L;

    private User user;
    private Role role;

    @ManyToOne
    public User getUser() { return user; }

    @ManyToOne
    public Role getRole() { return role; }
...
}
* 1021И, наконец, вот моя базовая сущность, для полноты:
@MappedSuperclass()
public abstract class Entity<X extends Entity<X>>
    implements Comparable<X>, Serializable
{
    private static final long serialVersionUID = 1L;
    private Long id;
    private Timestamp timestamp;
...
}

Я прочитал ссылку на Envers и просмотрел форум, но информация кажется довольно скудной.Любые идеи или указатели на это?

Ответы [ 2 ]

1 голос
/ 11 сентября 2012

Я использую Envers 4.1.3.Final, и у него определенно по-прежнему есть эта ошибка: для связей с @Embedded компонентами регистрирует запись аудита правильно в базе данных, но API запросов (forRevisionsOfEntity, в моем случае) просто не видит этого. Он вернул бы ревизию (MOD) для измененного объекта, но когда вы просматриваете фактическое свойство сущности, которое содержит ссылку на встроенный объект, оно всегда равно нулю для всех ревизий.

Я закончил тем, что написал обходной путь для запроса измененных значений с помощью собственного SQL (для затронутых свойств), так как мне не хотелось менять свое отображение просто для того, чтобы успокоить плагин с ошибками.

1 голос
/ 17 августа 2012

Я решил эту проблему, отбросив встраиваемый компонент UserRolePk и просто выбрав @JoinColumn, например,

public class UserRole extends Entity<UserRole>
{
    private User user;
    private Role role;

    public UserRole() {}

    @ManyToOne(fetch=FetchType.EAGER, optional=false)
    @JoinColumn(name="userid", referencedColumnName = "id", insertable=false, updatable=false)
    // XmlTransient used to prevent the following exception when JAXB marshals this into XML:
    //  com.sun.istack.SAXException2: A cycle is detected in the object graph. This will cause
    //  infinitely deep XML:
    @XmlTransient
    public User getUser() { return this.user; }

    @ManyToOne(fetch=FetchType.EAGER, optional=false)
    @JoinColumn(name="roleid", referencedColumnName = "id", insertable=false, updatable=false)
    public Role getRole() { return this.role; }
...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...