使用DomainClassConverter

时间:2017-07-31 20:11:02

标签: spring spring-mvc spring-data-jpa

我想在REST控制器中设置一对多关系,但我得到一个LazyInitializationException。我知道如何解决该异常(JOIN FETCH,EntityGraph),但不知道DomainClassConverter的上下文。

  

DomainClassConverter允许您在Spring中使用域类型   MVC控制器方法直接签名,这样就不必了   通过存储库手动查找实例

@Entity
public class Company implements Serializable {

    @OneToMany(mappedBy = "company")
    @JsonIgnore
    private Set<Contract> contracts = new HashSet<>();

    public Company addContract(Contract contract) {
        this.agreements.add(contract);
        contract.setCompany(this);
        return this;
    }

}

@Entity
public class Contract implements Serializable {

    @ManyToOne
    private Company company;

}

存储库:

@Repository
public interface CompanyRepository extends JpaRepository<Company, Long> {
}

@Repository
public interface ContractRepository extends JpaRepository<Company, Long> {
}

POST /api/companies/1/contracts请求映射createContract方法。参数已正确映射,因此我有一个Contract和一个Company实例。当我尝试将合同添加到公司时,我得到LazyInitializationException。我尝试在方法中添加@Transactional并在company.getContracts()上调用.size()来初始化集合,但它会抛出相同的异常。

@RestController
@RequestMapping("/api/companies/{companyId}")
public class CompanyContractResource {

    @PostMapping("/contracts")
    @Timed
    public ResponseEntity<Contract> createContract(@Valid @RequestBody Contract contract, @PathVariable("companyId") Company company) throws URISyntaxException {
        company.addContract(contract);
        Contract result = contractRepository.save(contract);
        return ResponseEntity.created(new URI("/api/contracts/" + result.getId()))
            .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString()))
            .body(result);
    }

}

2 个答案:

答案 0 :(得分:0)

尝试更改您的控制器方法:

public ResponseEntity<Contract> createContract(@Valid @RequestBody Contract contract, @PathVariable("companyId") Long companyId) throws URISyntaxException {

        // fetching a company explicitly 
        Company company = companyRepository.findOne(companyId); 

        company.addContract(contract);

        Contract result = contractRepository.save(contract);

        return ResponseEntity.created(new URI("/api/contracts/" + result.getId()))
            .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString()))
            .body(result);
}

相关信息:12

答案 1 :(得分:0)

我最终没有使用DomainClassConverter。我更改了存储库以获取延迟集合,然后添加Contract

@Repository
public interface CompanyRepository extends JpaRepository<Company, Long> {

    @Query(value = "SELECT c FROM Company c LEFT JOIN FETCH c.contracts WHERE c.id = ?1")
    Company findByIdWithContracts(Long id);

}

在控制器中:

@RestController
@RequestMapping("/api/companies/{companyId}")
public class CompanyContractResource {

    @PostMapping("/contracts")
    @Timed
    public ResponseEntity<Contract> createContract(@Valid @RequestBody Contract contract, @PathVariable("companyId") Long companyId) throws URISyntaxException {
        Company company = companyRepository.findByIdWithContracts(companyId);
        company.addContract(contract);
        Contract result = contractRepository.save(contract);
        return ResponseEntity.created(new URI("/api/contracts/" + result.getId()))
            .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString()))
            .body(result);
    }

}