0

J'utilise Hibernate Envers pour l'audit et j'ai un problème avec les clés primaires composites. J'ai beaucoup à beaucoup d'entités avec la clé primaire composée basée sur les propriétés relatives. La construction est comme suit:Hibernate Envers clé primaire composite relatedId request

@Entity 
@Audited 
@Table(indexes = { @Index(columnList = "person_id"), 
     @Index(columnList = "document_id") }) 
public class PersonDocument implements Serializable { 

    private static final long serialVersionUID = 1L; 

    @Id 
    @ManyToOne(optional = false, fetch = FetchType.EAGER) 
    private Document document; 

    @Id 
    @ManyToOne(optional = false, fetch = FetchType.EAGER) 
    private Person person; 

La relation n'est pas bidirectionnelle annotée. La clé primaire est correcte utilisée dans les tables auditées, comme le docu d'envers le décrit.

Mais maintenant je ne veux pas toutes les révisions qui se rapportent à la personne. Avec ce qui suit:

final AuditQuery query = AuditReaderFactory.get(entityManager) 
       .createQuery().forRevisionsOfEntity(PersonDocument.class, false, true) 
       .add(AuditEntity.relatedId("person").eq("12")) 
       .addOrder(AuditEntity.revisionNumber().desc()); 

Je me l'erreur suivante:

This criterion can only be used on a property that is a relation to another property. 

Si j'utilise une clé primaire non composite alors il fonctionne sans problèmes, mais je reçois l'erreur. Quelqu'un a-t-il une idée? La migration des données de la clé primaire composite vers une clé primaire supplémentaire pour plusieurs à plusieurs entités n'est pas si facile.

J'utilise la version 4.3.11 Mise en veille prolongée

Meilleures salutations

Répondre

1

Le problème ici est que fondamentalement ne Envers enregistre pas les relations pour @Id types annotés, ce qui est précisément la raison pour laquelle vous rencontrez cette erreur.

Malheureusement, Hibernate 4.3 n'est plus maintenu, donc toute correction de bogue que nous faisons serait applicable à Hibernate 5.x à ce stade, probablement 5.2.x. Cela dit, il existe une solution de contournement que vous pouvez utiliser pour éviter de devoir modifier votre configuration d'ID composite. L'idée est que vous créez une propriété qui masque les valeurs de clé composite-id et que vous utilisez la propriété shadow pour ces requêtes.

@Entity 
@Audited 
public class PersonDocument implements Serializable { 
    @Id 
    @ManyToOne(optional = false) 
    private Document document; // lets assume this maps to document_id 
    @Id 
    @ManyToOne(optional = false) 
    private Person person; // lets assume this maps to person_id 

    // we'll shadow those properties now 
    @Column(name = "document_id", nullable = false, insertable = false, updatable = false) 
    private Integer documentId; 

    @Column(name = "person_id", nullable = false, insertable = false, updatable = false) 
    private Integer personId; 
} 

maintenant plutôt que d'utiliser l'approche relatedId, nous pouvons interroger en fonction des propriétés simples:

reader.createQuery().forRevisionsOfEntity(PersonDocument.class, false, true) 
    .add(AuditEntity.property("personId").eq(42)) 
    .addOrder(AuditEntity.revisionNumber().desc()); 

Évidemment, cela est loin d'être idéal, mais vous pouvez certainement utiliser des choses comme @PostUpdate et @PostPersist pour conserve les différentes propriétés ombrées alignées avec leurs contre-parties d'objet.

+1

J'ai ajouté un JIRA lié à cette discussion ici: https://hibernate.atlassian.net/browse/HHH-11748 – Naros

+1

Le correctif pour cela s'est avéré assez simple. Nous avons juste besoin d'être en mesure d'effectuer un second passage sur les identifiants, tout comme nous le faisons pour les propriétés non-identifiant pour lier les associations et les propriétés des composants. – Naros