保存一个 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
属性。
有没有办法在同一查询中同时保存 race
和 stage
?
提前致谢,
托马斯
- 在 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
成为 toString
和 equals
方法的一部分。
或者当 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;
}
我试图用一个 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
属性。
有没有办法在同一查询中同时保存 race
和 stage
?
提前致谢, 托马斯
- 在 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
成为toString
和equals
方法的一部分。或者当 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;
}