6

I try to persist parent entity with one to many relation:

@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;
    }
...
}

and child entity:

@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;
....

}

So I recieve my TrainEx trainEx from json POST endpoint:

 @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}
    }]
 } 

after I save it like that:

...
@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);
    }
    ...

But I received SQL ERROR: null value in column "trainid" violates not-null constraint, but as you see I setted trainEx entity to TrainCompositionEx, and I stopped in debug mode and trainId exists there: enter image description here so what should I do?

UPDATE1: I investigated logs and think that problem in that childs persist before parent entity, because I insert into train_composition table, but not into train table see:

Hibernate: insert into tms.public.train_composition (version, transportOrderId, wagonId, trainId) values (?, ?, ?, ?)
MeetJoeBlack
  • 2,804
  • 9
  • 40
  • 66
  • You are using trainCompositionEx.setTrainByTrainId(trainEx); and saving TrainEx, but creating and using TrainEx1 everywhere else. This code doesn't make sense, as what is the new TrainEx1 for, and what does trainCompositionEx.setTrainByTrainId(trainEx) do? Shouldn't the TrainCompositionEx get added to trainEx's trainCompositionsByTrainId list instead of creating a new trainEx1 and new trainCompositionExes list? – Chris Mar 22 '16 at 19:50
  • sorry, my bad.. I wiil edit my post – MeetJoeBlack Mar 22 '16 at 20:11
  • updated, pls walk through my post – MeetJoeBlack Mar 22 '16 at 20:30

1 Answers1

4

I use em.persist for persisting classes. My parent entity has

@JsonProperty(TIMES)
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true)
private Set<Times> timesList = new HashSet<Times>();

while the child has

@JsonIgnore
@ManyToOne(cascade = CascadeType.ALL)
private Rider rider;

The code is

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

for a new rider, for an existing rider I merge the new data into the old object. The project is here: https://github.com/xtien/motogymkhana-server The code is from RiderDaoImpl and Rider and Times. This is what the project is for: http://www.gymcomp.com/eu

Christine
  • 5,617
  • 4
  • 38
  • 61
  • I cant persist rider first because I received full object with childs from json. So if I do em.persist(parent) it already has childs inside – MeetJoeBlack Mar 22 '16 at 21:27
  • In my example, I persist a Rider, with multiple Times objects. None are preexisting. For a pre-existing Rider, my code doesn't do em.merge or anything. If you have a pre-existing child with a new parent, you should have a look at your datamodel. If you have a pre-existing parent with a new child, you can just add the child to the persisted parent. – Christine Mar 22 '16 at 21:32
  • I solved my problem using em.persist() instead of spring-data-jpa's SAVE() method. – MeetJoeBlack Mar 22 '16 at 21:33
  • Sorry, byt I thikk that spring data jpa SAVE() calls em.persist inside, but its seems somethinhg strange happend – MeetJoeBlack Mar 22 '16 at 21:37
  • Maybe you know, if i use em.merge instead of em.persists, why did it try to save child entity first? – MeetJoeBlack Mar 22 '16 at 21:55
  • Don't use em.merge, unless you've read the documentation and you know exactly what merge does. Generally, you don't want to do a merge, just a persist, initially. After the persist, JPA handles persistence for you. This is a summary, it has a link to the JPA documentation: http://stackoverflow.com/questions/4509086/what-is-the-difference-between-persist-and-merge-in-hibernate – Christine Mar 23 '16 at 08:06