为什么用JPA不能更改实体的引用对象?

时间:2019-09-17 07:41:36

标签: java spring spring-boot spring-data-jpa spring-data

我有一个票证对象,应该对其进行编辑。在我的票证对象中有引用对象的属性(请参见下文)。

...
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "project_id", referencedColumnName="id")
private Project project;

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "costCenter_id", referencedColumnName="id")
private CostCenter costCenter;
...

但是当我尝试更新实体时,总是会出现错误:

  

无法提交JPA交易;嵌套的异常是javax.persistence.RollbackException:提交事务时出错

@PutMapping("/tickets/{id}")
@ResponseStatus(HttpStatus.OK)
public Ticket updateTicket(@RequestBody Ticket ticket) throws Exception{
    Optional<Ticket> o = this.ticketRepo.findById(ticket.getId());
    o.ifPresent(element -> {
        if(ticket.getCostCenter() != null) {
            Optional<CostCenter> c = this.costCenterRepo.findById(ticket.getCostCenter().getId());
            c.ifPresent( costCenter -> {
                element.setCostCenter(costCenter);
            });
        }
        if(ticket.getProject() != null) {
            Optional<Project> p = this.projectRepo.findById(ticket.getProject().getId());
            p.ifPresent(project -> {
                element.setProject(project);
            });
        }
        this.ticketRepo.save(element);
    });
    return o.orElseThrow(() -> new NotFoundException(ticket.getId()));
}

PS:当我触发更新而不进行任何更改时,一切正常。

Stacktrace:https://textsaver.flap.tv/lists/2vm5

class AuditorAwareImpl implements AuditorAware<Long> {

    @Override
    public Optional<Long> getCurrentAuditor() {
        PersonRepository personRepo = ApplicationContextProvider.getApplicationContext().getBean(PersonRepository.class);
        if(SecurityContextHolder.getContext().getAuthentication() != null) {
            Person p = personRepo.findByUserPrincipalName(SecurityContextHolder.getContext().getAuthentication().getName() + "@email.com");
            return Optional.of(p.getId());
        } else {
            Person p = personRepo.findByUserPrincipalName("SYSTEM");
            return Optional.of(p.getId());
        }
    }
}

@Component(value = "applicationContextProvider")
class ApplicationContextProvider implements ApplicationContextAware {

    private static class AplicationContextHolder {
        private static final InnerContextResource CONTEXT_PROV = new InnerContextResource();
    }

    private static final class InnerContextResource {

        private ApplicationContext context;

        private void setContext(ApplicationContext context) {
            this.context = context;
        }
    }

    public static ApplicationContext getApplicationContext() {
        return AplicationContextHolder.CONTEXT_PROV.context;
    }

    @Override
    public void setApplicationContext(ApplicationContext ac) {
        AplicationContextHolder.CONTEXT_PROV.setContext(ac);
    }

}
@Data
@Getter
@Setter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class BaseEntity implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", updatable = false, nullable = false)
    protected Long id;

    @CreatedDate
    private Date createdAt;

    @CreatedBy
    private Long createdBy;

    @LastModifiedDate
    private Date updatedAt;

    @LastModifiedBy
    private Long updatedBy;

    @PrePersist
    protected void prePersist() {
        if (this.createdAt == null) createdAt = new Date();
        if (this.updatedAt == null) updatedAt = new Date();
    }

    @PreUpdate
    protected void preUpdate() {
        this.updatedAt = new Date();
    }

    @PreRemove
    protected void preRemove() {
        this.updatedAt = new Date();
    }

}

1 个答案:

答案 0 :(得分:4)

您有一个StackOverflowError,强烈建议您在某处(或至少是一个很深的地方)进行了无限递归:

Caused by: java.lang.RuntimeException: java.lang.StackOverflowError

com.mycompany.test.config.AuditorAwareImpl.getCurrentAuditor在您很长的堆栈跟踪中反复出现的事实表明,它以某种方式参与了您的无限递归,我敢打赌,它是由此类引发的,无论如何首先触发了它可能org.springframework.data.auditing.AuditingHandler。因此,请检查您的AuditorAwareImpl代码和/或审核配置。