SpringData CrudRepository自动应用级联类型

时间:2018-10-10 14:47:59

标签: java spring hibernate jpa cascade

在我的项目中,我必须连接到现有数据库并执行更新两个表的逻辑。

我的设置如下:

@Entity
@Table(name = "DOCUMENTCONTENT")
@Getter
public class DocumentContent {

    @Id
    @Column(name = "ID", insertable = false, updatable = false)
    private Long id;

    @OneToOne
    @JoinColumn(name = "DOCUMENT_ID", insertable = false, updatable = false)
    private Document document;

    @Lob
    @Column(name = "CONTENT")
    @Setter
    private byte[] content;
}

@Entity
@Table(name = "DOCUMENT")
@Getter
public class Document {

    @Id
    @Column(name = "ID", insertable = false, updatable = false)
    private Long id;

    @OneToOne(mappedBy = "document")
    private DocumentContent documentContent;

    @OneToMany(mappedBy = "document", fetch = EAGER)
    private List<Attachment> attachments;
}

@Entity
@Table(name = "ATTACHMENT")
@Getter
public class Attachment {

    @Id
    @Column(name = "ID")
    private Long id;

    @ManyToOne
    @JoinColumn(name = "DOCUMENT_ID", insertable = false, updatable = false)
    private Document document;

    @ManyToOne
    @JoinColumn(name = "CONTRACT_ID",updatable = false, insertable = false)
    private Contract contract;
}

@Entity
@Table(name = "CONTRACT")
@Getter
public class Contract {

    @Id
    @Column(name = "ID", insertable = false, updatable = false)
    private Long id;

    @Column(name = "STATUS")
    @Setter
    private String status;

    @ManyToOne
    @JoinColumn(name = "CUSTOMER_ID", insertable = false, updatable = false)
    private Customer customer;

    @OneToMany(mappedBy = "contract", fetch = EAGER)
    private List<Attachment> attachments;
}

@Service
public class MyServiceImpl implements MyService {

    @Autowired
    private DocumentContentRepository documentContentRepository; // spring data Crud Repository

    @Override
    @Transactional
    public void updateDocumentContent(SomeDto someDto) {
        DocumentContent documentContent = documentContentRepository.findByDocumentId(someDto.getDocumentId());
        documentContent.setContent(someDto.getBytes());
        List<Contract> contracts = documentContent.getDocument().getAttachments()
                .stream().map(Attachment::getContract).collect(toList());
        contracts.forEach(contract -> contract.setStatus("SIGNED"));
        documentContentRepository.save(documentContent);
    }
}

当我从上述服务中触发方法时,我可以在控制台输出中注意到那些SQL:

  

休眠:更新documentcontent集合content =?其中id =?
  休眠:更新合同集状态=? id =?

我了解为什么jpa在documentcontent表中执行第一次更新,但是我也不知道为什么在contract表中也进行更新。如您所见,我没有在任何实体中使用CascadeType.MERGE

您能解释一下为什么执行第二个更新而不声明级联类型吗?

2 个答案:

答案 0 :(得分:1)

由于该原因,您正在获取第二个查询,您正在修改“合同”的“状态”属性。 JPA会检测到此更改并尝试更新实体。

这是@OneToMany的默认CaseCadeType行为

要进一步阅读,请遵循此link

答案 1 :(得分:1)

我怀疑它与Cascade完全无关,但与事务性写后置机制(more info)有关。我相信您也可以摆脱困境

documentContentRepository.save(documentContent);

因为您要修改两个管理实体。在事务结束时,休眠将保留所有由脏检查机制(more info)标记为已修改的实体。