Cerco di registrare eventuali modifiche delle entità JPA. Per questa ragione ciascuna entità eredita da una classe di entità astratta che ha una lista di oggetti LogEntry.Modifiche al rilevamento JPA di EclipseLink
classe AbstractEntity: classe
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@EntityListeners(ChangeListener.class)
public abstract class AbstractEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Version
private Long version;
@Temporal(TemporalType.DATE)
private Date validFrom;
@Temporal(TemporalType.DATE)
private Date validTo;
private String name;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "abstractEntity")
private List<LogEntry> logEntry = new ArrayList<LogEntry>();
//getter and setter
}
LogEntry:
@Entity
public class LogEntry extends AbstractEntity {
@ManyToOne
@JoinColumn
protected AbstractEntity abstractEntity;
@ManyToOne
@JoinColumn
protected Person person; // creator or updater
@Column(updatable=false, insertable=false, columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
@Temporal(TemporalType.TIMESTAMP)
protected Date changeDate;
protected String comment;
//getter and setter
}
Il mio approccio a questo è stato quello di creare un nuovo oggetto LogEntry e aggiungerlo alla lista LogEntry dell'entità prima che un'entità ottenuto aggiornato o persisteva .
Ho provato le seguenti soluzioni:
- Uso delle annotazioni callback (@PreUpdate, @PrePersist ecc) direttamente in classe entità o separato in un ascoltatore entità collegata con AbstractEntity
- Uso DescriptorEvent e di EclipsLink la corrispondenti metodi di callback in un listener di entità. Questo è stato il processo più promettente. In preUpdate potrei aggiungere un nuovo LogEntry all'oggetto interessato. Il LogEntry aggiunto è stato persino mantenuto correttamente, ma preUpdate verrà richiamato da qualsiasi operazione di database (selezionare porta anche al richiamo di preUpdate), quindi non posso differire tra un oggetto modificato e un oggetto senza modifiche. I changeset forniti dall'evento descrittore, dalla query correlata o da unitOfWork sono in ogni caso nulli. Un confronto tra l'oggetto corrente e il vecchio oggetto (fornito dall'evento descrittore) è IMHO troppo complesso, non è vero? D'altra parte, in preUpdateWithChanges potrei facilmente rilevare un'entità modificata, ma a questo punto è apparentemente troppo tardi per aggiungere un log-in. La logentry non verrà mantenuta.
Quasi ognuna di queste prove mi consente di modificare gli attributi (come nome o validTo) dell'entità interessata. Ma nessuna soluzione offre l'opportunità di creare una nuova istanza di LogEntry, o piuttosto di mantenere questa istanza di LogEntry. Ho anche cercato di ottenere un'istanza di un bean di sessione tramite jndi lookup per mantenere manualmente LogEntry. La ricerca jndi funziona, ma chiamare i metodi di creazione o aggiornamento del bean di sessione non ha alcun effetto.
Il mio attuale ascoltatore entità simile a questa:
public class ChangeListener extends DescriptorEventAdapter {
@Override
public void preUpdate(DescriptorEvent event) {
AbstractEntity entity = (AbstractEntity) event.getObject();
if (!(entity instanceof LogEntry)) {
LogEntry logEntry = new LogEntry();
logEntry.setPerson(getSessionController().getCurrentUser());
logEntry.setAbstractEntity(entity);
entity.getLogEntries().add(logEntry);
}
}
}
Hibernate Envers è per vari motivi alcuna opzione.
La versione di EclipseLink è 2.3.2.
Considerare anche il supporto della cronologia di EclipseLink, http://wiki.eclipse.org/EclipseLink/Examples/JPA/History – James