@OneToMany关系中merge()的奇怪行为

时间:2016-06-10 06:50:38

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

我在两个实体之间有简单的关系

  

One-Reservation - >许多座位

实体

@Entity
public class Reservation implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long reservationId;
    private String reservationDate;

    private static final long serialVersionUID = 1L;

    @OneToMany(mappedBy = "reservation",  fetch = FetchType.EAGER, cascade = {CascadeType.ALL})
    @Fetch(value = FetchMode.SUBSELECT)
    private List<Seat> seats = new CopyOnWriteArrayList<Seat>();
    // omitting get()s and set()s
}

@Entity
public class Seat implements Serializable {

    @Id
    @GeneratedValue (strategy = GenerationType.IDENTITY)
    private Long seatId;
    private Integer seatNumber;
    private static final long serialVersionUID = 1L;

    @JsonIgnore
    @ManyToOne(cascade=CascadeType.ALL)
    @JoinColumn(name = "reservationId")
    private Reservation reservation;
     // omitting get()s and set()s
}

首先,我保存预订信息,然后在控制器中保存座位信息

@RequestMapping(value = "/proceed", method = RequestMethod.POST)
public String checkOut(@ModelAttribute("passenger")Passenger passenger,
        @RequestParam("bus_id") String busId,
        @RequestParam("seats")List<Seat> seats) {

    passengerService.save(passenger);
    try {
        System.out.println("List size is " + seats.size());
        Bus selectedBus = busService.getById(Long.valueOf(busId));

        Reservation reservation = new Reservation();
        reservation.setBus(selectedBus);
        reservation.setPassenger(passenger);
        reservation.setReservationDate(new Date().toString());  
        // Saving reservation info here        
        reservationService.save(reservation);

        passenger.setReservation(reservation);
        passenger.setBus(selectedBus);
        passengerService.update(passenger);

        for (Seat seat : seats) {               
            seat.setBus(selectedBus);           
            seat.setReservation(reservation);// Here it gives weird results see details bellow 
            seatService.save(seat);
        }

    } catch (Exception e) {
        System.out.println("Error is " + e.getMessage());
        System.out.println("Cause is " + e.getCause());
        e.printStackTrace();
    }

    return "reservation";
}

以下代码

for (Seat seat : seats) {               
    seat.setBus(selectedBus);           
    seat.setReservation(reservation);
    seatService.save(seat);
}

SeatService save()是

@Override
public void save(Seat e) {
    entityManager.merge(e);
}

它在保留表中保存seats.size()次预订对象的相同信息在使用reservationService.save(reservation);之前保存了相同的信息,我发现导致此结果的行

@JsonIgnore
@ManyToOne(cascade=CascadeType.ALL)// this line causes that weird behavior
@JoinColumn(name = "reservationId")
private Reservation reservation;

如果我删除cascade=CascadeType.ALL,我会

org.hibernate.PersistentObjectException: detached entity passed to persist:

我还尝试将cascade=CascadeType.ALL更改为cascade=CascadeType.PERSIST,仍然得到相同的结果(即它仍然可以在预订表中节省seats.size()倍的预订对象。)

请解决此问题。

1 个答案:

答案 0 :(得分:0)

请不要使用merge来保存新实体。 来自here

  

将给定对象的状态复制到具有相同标识符的持久对象上。如果当前没有与会话关联的持久性实例,则将加载该实例。返回持久化实例。 如果给定实例未保存,请保存副本并将其作为新的持久实例返回。给定的实例不会与会话关联。如果关联是使用cascade =&#34; merge&#34;映射的,则此操作会级联到关联的实例。

这意味着你的实例reservation不是持久的,每次在级联时,hibernate会自动插入它。

请尝试entityManager.persist,或者你必须做出类似的事情:

ReservationService:

@Override
public Reservation save(Seat e) {
    return entityManager.merge(e);
}

和控制器:

@RequestMapping(value = "/proceed", method = RequestMethod.POST)
public String checkOut(...) {
    ...
    Reservation reservation = new Reservation();
    ...
    reservation = reservationService.save(reservation);
    ...
}