2016-08-08 4 views
1

Я настроил аудит JPA с помощью Spring Data JPA AuditingEntityListener и AuditorAware bean. Я хочу, чтобы иметь возможность сохранять данные аудитора даже на объектах с предопределенными идентификаторами. Проблемы заключается в том, что, когда JPA объект с предопределенным идентификатором в настоящее время сохраняется и продувает его аудиторские детали не могут быть сохранена:Spring Data JPA аудит терпит неудачу, когда сохраняется удаленный объект

ссылки на объекты неспасенной переходная экземпляры - сохранить переходный экземпляр перед промывкой: me.auditing.dao.AuditorDetails

Интересная часть заключается в том, что когда объект с сгенерированным идентификатором сохраняется - все в порядке. В обоих случаях объекты новы. Я не мог определить проблему, копаясь в спящем коде, поэтому я создал 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: Похоже, что когда новый объект с предопределенным идентификатором сохраняется, он получает два разных экземпляра createdBy и modifiedBy AuditorDetails, что вполне логично, если объект не будет фактически новым. Таким образом, совершенно новый объект сгенерированный получает как AuditorDetails одного и того же экземпляра, так и тот, у которого с установленным вручную идентификатором нет. Я проверил его, сохранив данные аудитора в компоненте AuditorAware, прежде чем возвращать его в AuditingHandler.

ответ

1

Итак, сейчас единственное решение, которое я мог бы найти это на самом деле сохраняться AuditorDetails перед записью аудируемых лиц, как так:

@Override 
@Transactional 
public AuditorDetails getCurrentAuditor() { 
    AuditorDetails details = new AuditorDetails() 
      .setId(null) 
      .setUserId("someUserId") 
      .setDivisionId("someDivisionId"); 
    return auditorDetailsRepository.save(details); 
} 

Это не самое элегантное решение, но он работает в настоящее время.

Смежные вопросы