Я установил аудит JPA с помощью Spring Data JPA AuditingEntityListener и AuditorAware bean. Я хочу иметь возможность сохранять данные аудитора даже для сущностей с предопределенными идентификаторами. Проблема в том, что когда объект JPA с предопределенным идентификатором сохраняется и сбрасывается, данные аудитора не могут быть сохранены:
объект ссылается на несохраненный временный экземпляр - сохраните временный экземпляр перед сбросом: me.auditing.dao.AuditorDetails
Интересно то, что когда сущность со сгенерированным идентификатором сохраняется - все в порядке. В обоих случаях объекты новые. Я не смог точно определить проблему, копаясь в коде гибернации, поэтому я создал образец проекта, чтобы продемонстрировать это (тестовый класс me.auditing.dao.AuditedEntityIntegrationTest) В нем есть как объекты с предопределенными, так и сгенерированными идентификаторами, и он должен подвергаться аудиту.
Сущности:
@Entity
public class AuditedEntityWithPredefinedId extends AuditableEntity {
@Id
private String id;
public String getId() {
return id;
}
public AuditedEntityWithPredefinedId setId(String id) {
this.id = id;
return this;
}
}
а также:
@Entity
public class AuditedEntityWithGeneratedId extends AuditableEntity {
@Id
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid")
private String id;
public String getId() {
return id;
}
public AuditedEntityWithGeneratedId setId(String id) {
this.id = id;
return this;
}
}
где родительский класс:
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class AuditableEntity implements Serializable {
private static final long serialVersionUID = -7541732975935355789L;
@ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.ALL})
@CreatedBy
private AuditorDetails createdBy;
@CreatedDate
private LocalDateTime createdDate;
@ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.ALL})
@LastModifiedBy
private AuditorDetails modifiedBy;
@LastModifiedDate
private LocalDateTime modifiedDate;
И реализация геттера аудитора:
@Override
public AuditorDetails getCurrentAuditor() {
return new AuditorDetails()
.setId(null)
.setUserId("someUserId")
.setDivisionId("someDivisionId");
}
Редактировать 08.08.2016: Похоже, что когда новая сущность с предопределенным идентификатором сохраняется, она получает два разных экземпляра createdBy и modifiedBy AuditorDetails, что вполне логично, если сущность на самом деле не новый. Таким образом, совершенно новый объект со сгенерированным именем получает AuditorDetails одного и того же экземпляра, а объект с идентификатором, установленным вручную, - нет. Я протестировал его, сохранив детали аудитора в bean-компоненте AuditorAware, прежде чем возвращать его в AuditingHandler.