Question

I ai une entité chargée par mise en veille prolongée (via EntityManager):

User u = em.load(User.class, id)

Cette classe est auditée par Hibernate Envers. Comment puis-je charger la version précédente d'une entité utilisateur?

Était-ce utile?

La solution

peut-être ce alors (de AuditReader documents)

AuditReader reader = AuditReaderFactory.get(entityManager);
User user_rev1 = reader.find(User.class, user.getId(), 1);

List<Number> revNumbers = reader.getRevisions(User.class, user_rev1);
User user_previous = reader.find(User.class, user_rev1.getId(),
  revNumbers.get(revNumbers.size()-1));

(je suis très nouveau à cela, pas sûr si j'ai tout le droit de syntaxe, peut-être la taille () - 2? - 1 devrait être de taille ())

Autres conseils

Voici une autre version qui trouve la version précédente par rapport à un numéro de révision « en cours », il peut être utilisé même si l'entité que vous regardez est pas la dernière révision. Il gère également le cas où ne sont pas une révision préalable. (em est supposé être un EntityManager précédemment peuplé)

public static User getPreviousVersion(User user, int current_rev) {
    AuditReader reader = AuditReaderFactory.get(em);

    Number prior_revision = (Number) reader.createQuery()
    .forRevisionsOfEntity(User.class, false, true)
    .addProjection(AuditEntity.revisionNumber().max())
    .add(AuditEntity.id().eq(user.getId()))
    .add(AuditEntity.revisionNumber().lt(current_rev))
    .getSingleResult();

    if (prior_revision != null)
        return (User) reader.find(User.class, user.getId(), prior_revision);
    else
        return null
}

Ceci peut être généralisé à:

public static T getPreviousVersion(T entity, int current_rev) {
    AuditReader reader = AuditReaderFactory.get(JPA.em());

    Number prior_revision = (Number) reader.createQuery()
    .forRevisionsOfEntity(entity.getClass(), false, true)
    .addProjection(AuditEntity.revisionNumber().max())
    .add(AuditEntity.id().eq(((Model) entity).id))
    .add(AuditEntity.revisionNumber().lt(current_rev))
    .getSingleResult();

    if (prior_revision != null)
        return (T) reader.find(entity.getClass(), ((Model) entity).id, prior_revision);
    else
        return null
}

Le seul peu délicat avec cette généralisation devient l'identifiant de l'entité. Parce que j'utilise le Play! cadre, je peux exploiter le fait que toutes les entités sont des modèles et utilisent ((Model) entity).id pour obtenir l'ID, mais vous devrez régler ce en fonction de votre environnement.

Je pense que ce serait ceci:

final AuditReader reader = AuditReaderFactory.get( entityManagerOrSession );

// This could probably be declared as Long instead of Object
final Object pk = userCurrent.getId();

final List<Number> userRevisions = reader.getRevisions( User.class, pk );

final int revisionCount = userRevision.size();

final Number previousRevision = userRevisions.get( revisionCount - 2 );

final User userPrevious = reader.find( User.class, pk, previousRevision );

A partir de la documentation:

AuditReader reader = AuditReaderFactory.get(entityManager);
User user_rev1 = reader.find(User.class, user.getId(), 1);

Bâtiment hors de l'excellente approche de @ brad-Mace, j'ai apporté les modifications suivantes:

  • Vous devez passer dans votre EntityClass et Id au lieu de hardcoding et en supposant que le modèle.
  • Ne pas hardcode votre EntityManager.
  • Il n'y a pas défini le point selectDeleted, car un enregistrement supprimé ne peut jamais être retourné comme la révision précédente.
  • Appel à obtenir le résultat unique et lancer exception si aucun résultat ou plus de 1 résultat se trouve, donc soit appeler ou prendre le de résultats exception (cette solution appelle getResultList avec maxResults = 1)
  • Obtenir la révision, le type et l'entité dans une transaction (supprimer la projection, utiliser orderBy et maxResults, et la requête pour l'objet [3])

Alors, voici une autre solution:

public static <T> T getPreviousRevision(EntityManager entityManager, Class<T> entityClass, Object entityId, int currentRev) {
    AuditReader reader = AuditReaderFactory.get(entityManager);
    List<Object[]> priorRevisions = (List<Object[]>) reader.createQuery()
            .forRevisionsOfEntity(entityClass, false, false)
            .add(AuditEntity.id().eq(entityId))
            .add(AuditEntity.revisionNumber().lt(currentRev))
            .addOrder(AuditEntity.revisionNumber().desc())
            .setMaxResults(1)
            .getResultList();

    if (priorRevisions.size() == 0) {
        return null;
    }
    // The list contains a single Object[] with entity, revinfo, and type 
    return (T) priorRevision.get(0)[0];
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top