SPRING DATA JPA保存@OneToMany关系

6

我尝试使用一对多关系持久化父实体:

@Entity
public class TrainEx  {
    private Set<TrainCompositionEx> trainCompositionsByTrainId;
    @OneToMany(cascade = {CascadeType.ALL}, fetch = FetchType.LAZY,  mappedBy = "trainByTrainId")
    public Set<TrainCompositionEx> getTrainCompositionsByTrainId() {
        return trainCompositionsByTrainId;
    }

    public void setTrainCompositionsByTrainId(Set<TrainCompositionEx> trainCompositionsByTrainId) {
        this.trainCompositionsByTrainId = trainCompositionsByTrainId;
    }
...
}

以及子实体:

@Entity
public class TrainCompositionEx{
    @Id
    @ManyToOne(cascade = {CascadeType.REFRESH}, fetch = FetchType.LAZY)
    @JoinColumn(name = "trainId", referencedColumnName = "trainId", nullable = false, insertable = true, updatable = true)
    private TrainEx trainByTrainId;
....

}

所以我通过json POST端点收到了我的TrainEx培训材料:

 @RequestMapping(method= RequestMethod.POST, consumes = "application/json", produces = "application/json")
    public @ResponseBody
    ResponseEntity<Void> addTrain(@RequestBody TrainEx trainEx) throws Exception {
        trainService.add(trainEx);
        return new ResponseEntity<Void>(HttpStatus.CREATED);
    }

JSON:

 {
    "trainId" : 5,
    "status" :  1,
    "maxWeight" :  200,
    "maxLength" :  35,
    "speed" :  60,
    "totalWeight" : 100,
    "totalLength" : 20,
    "trainCompositionsByTrainId": [{
        "wagonByWagonId": {"wagonId" : 2}
    }]
 } 

我将其保存后:

...
@Transactional
    public TrainEx add(TrainEx trainEx) {

    for(TrainCompositionEx trainCompositionEx : trainEx.getTrainCompositionsByTrainId()){
        trainCompositionEx.setTrainByTrainId(trainEx);
        trainCompositionEx.setWagonByWagonId(
                em.getReference(WagonEx.class, trainCompositionEx.getWagonByWagonId().getWagonId()));
    }
    return trainExRepository.save(trainEx);
    }
    ...

但我收到了SQL错误:"null value in column "trainid" violates not-null constraint",但是你可以看到我已经将实体trainEx设置为TrainCompositionEx,而且我在调试模式下停止并检查过trainId存在:enter image description here,那么我该怎么办呢?
更新1: 我研究了日志,认为问题在于子实体在父实体之前持久化,因为我插入train_composition表,而不是train表,请参考:
Hibernate: insert into tms.public.train_composition (version, transportOrderId, wagonId, trainId) values (?, ?, ?, ?)

你正在使用trainCompositionEx.setTrainByTrainId(trainEx)并保存TrainEx,但在其他地方创建和使用TrainEx1。这段代码没有意义,因为新的TrainEx1是用来做什么的?trainCompositionEx.setTrainByTrainId(trainEx)又是做什么的?难道不应该将TrainCompositionEx添加到trainEx的trainCompositionsByTrainId列表中,而不是创建一个新的trainEx1和新的trainCompositionExes列表吗? - Chris
抱歉,我的错。我会编辑我的帖子。 - MeetJoeBlack
更新了,请浏览我的帖子。 - MeetJoeBlack
1个回答

4
我使用 em.persist 来将类持久化。我的父实体有:
@JsonProperty(TIMES)
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
private Set<Times> timesList = new HashSet<Times>();

当孩子拥有…
@JsonIgnore
@ManyToOne(cascade = CascadeType.ALL)
private Rider rider;

代码如下:

em.persist(rider);
for (Times t : rider.getTimes()) {
    t.setRider(rider);
}

对于新手车手,对于现有的车手,我将新数据合并到旧对象中。此项目在这里:https://github.com/xtien/motogymkhana-server 。代码来自 RiderDaoImplRider 以及 Times 。该项目的用途是:http://www.gymcomp.com/eu

我无法持久化骑手的第一个对象,因为我从JSON中接收到了带有子对象的完整对象。因此,如果我执行em.persist(parent),它已经包含了子对象。 - MeetJoeBlack
在我的示例中,我持久化了一个Rider,其中包含多个Times对象。没有任何预先存在的对象。对于已经存在的Rider,我的代码不执行em.merge或其他操作。如果您有一个具有新父级的预先存在的子级,则应查看您的数据模型。如果您有一个具有新子级的预先存在的父级,则可以将该子级添加到已持久化的父级中。 - Christine
我使用em.persist()方法解决了我的问题,而不是使用spring-data-jpa的SAVE()方法。 - MeetJoeBlack
抱歉,但我认为Spring Data JPA的SAVE()方法内部调用了em.persist,但似乎出现了一些奇怪的情况。 - MeetJoeBlack
也许你知道,如果我使用 em.merge 而不是 em.persist,为什么它会尝试先保存子实体? - MeetJoeBlack
除非您已阅读文档并确切了解merge的作用,否则请勿使用em.merge。通常,您只需进行持久化操作,而不是合并操作。在持久化之后,JPA会为您处理持久性。这是一个摘要,其中包含指向JPA文档的链接:https://dev59.com/kW855IYBdhLWcg3wJgxy - Christine

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接