我使用Spring Data JPA AuditingEntityListener和AuditorAware bean设置了JPA审核。我想要的是能够在具有预定义标识符的实体上保留审计员详细信息。 问题是当具有预定义id的JPA实体被持久化并刷新时,审计者的详细信息无法保留:
对象引用未保存的瞬态实例 - 在刷新之前保存瞬态实例:me.auditing.dao.AuditorDetails
有趣的是,当保存具有生成ID的实体时 - 一切都很好。在这两种情况下,实体都是新的。我无法确定通过hibernate代码挖掘的问题所以我创建了一个sample project来演示这个(测试类 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");
}
编辑2016-08-08:似乎当保存具有预定义ID的新实体时,它会获得createdBy和modifiedBy AuditorDetails的两个不同实例,如果实体不能实现,则这是非常合理的实际上是新的。因此,生成的全新实体将获得相同实例的AuditorDetails,而具有手动设置ID的实体则不会。我在AuditorAware bean中保存审核员详细信息之前对其进行了测试,然后再将其返回到AuditingHandler。
答案 0 :(得分:1)
好的,现在我能找到的唯一解决方案是在将AuditorDetails写入审计实体之前实际保留它:
@Override
@Transactional
public AuditorDetails getCurrentAuditor() {
AuditorDetails details = new AuditorDetails()
.setId(null)
.setUserId("someUserId")
.setDivisionId("someDivisionId");
return auditorDetailsRepository.save(details);
}
这不是最优雅的解决方案,但它现在可以使用。