保存一个 object 和一个嵌套的 object,只有一个 Repository 保存请求

Save an object and a nested object with only one Repository save request

我试图用一个 JpaRepository 请求保存一个 object 和一个嵌套的 object。 所以我使用了 parent object 的存储库的保存方法。 有我的实体:

Parent

@Entity
@Data
@Table(name = "race")
@NoArgsConstructor
public class Race {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected int id;

private String name;

@OneToMany(cascade = CascadeType.ALL, mappedBy = "race")
private List<Stage> stages;

// some others attributes

}

嵌套

@Data
@Entity
@Table(name = "stage")
@NoArgsConstructor 
public class Stage {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected int id;

String traceName;

@ManyToOne
@JoinColumn(name = "race_id", nullable = false, foreignKey = @ForeignKey(name = "stage_fk_race"))
private Race race;

//some other attributes

}

我正在使用 swagger 来尝试保存。这是我的查询正文:

{
  "name": "Trail du Clair de Lune",
  "stages": [
    {
      "traceName": "trail_8km.gpx",
    }
  ]
}

我的控制器:

@RestController
@RequestMapping(value = "/race", produces = MediaType.APPLICATION_JSON_VALUE)
public class RaceController {

private final RaceService raceService;

@Autowired
public RaceController(RaceService raceService) {
    this.raceService = raceService;
}

@PostMapping(value = "save")
public Race save(@RequestBody Race race) {
    System.out.println(race.toString());
    return raceService.save(race);
}

@GetMapping(path = "/{id}")
public Race getOne(@PathVariable Integer id) {
    Optional<Race> byId = raceService.findById(id);

    if(byId.isPresent()) {
        return byId.get();
    } else return null;
    }
}

我的服务:

@Service
public class RaceServiceImpl implements RaceService {

private RaceRepository raceRepository;

@Autowired
public RaceServiceImpl(RaceRepository raceRepository) {
    this.raceRepository = raceRepository;
}

@Override
public Race save(Race race) {
    return raceRepository.save(race);
}

@Override
public Optional<Race> findById(Integer id) {
    return raceRepository.findById(id);
    }
    
}

我的存储库:

    @Repository
public interface RaceRepository extends JpaRepository<Race, Integer> {

}

我收到这个错误:

"message": "org.hibernate.exception.ConstraintViolationException: could not execute statement"

我认为嵌套的object stage先保存。所以 parent id 还不存在,它不能设置 race_id 属性。

有没有办法在同一查询中同时保存 racestage

提前致谢, 托马斯

  • 在 JPA/Hibernate 中,您必须明确设置 bi-directioanl 关系。当 jackson 创建 race 对象时,它将具有 stage 对象列表。但是 stage 个对象不会有 race 个对象。
     @PostMapping(value = "save")
     public Race save(@RequestBody Race race) {
        System.out.println(race.toString());
        race.getStages().forEach(stage -> stage.setRace(race));
        return raceService.save(race);
     }
  • 标记为Optional=false
    @ManyToOne(optional = false)
    @JoinColumn(name = "race_id".....)
    private Race race;

更新

您遇到的第二个错误不是因为休眠。

  • 您正在尝试打印或调试已保存的 race 对象,而 Lombok 生成的 toString 对象进入无限递归。为避免这种情况,请勿使 stages 成为 toStringequals 方法的一部分。

  • 或者当 Jackson 将保存的 race 翻译成 json 时,无限递归正在发生。有很多方法可以告诉杰克逊避免它,但最简单的方法是

    @PostMapping(value = "save")
     public Race save(@RequestBody Race race) {
        System.out.println(race.toString());

        race.getStages().forEach(stage -> stage.setRace(race));
        Race saved = raceService.save(race);

        saved.getStages().forEach(stage -> stage.setRace(null));
        return saved;
     }