2017-10-20 161 views
7

我有以下3種型號:對象引用一個未保存的瞬態的實例 - 沖洗之前保存的瞬態的實例:春數據JPA

模型1:預訂

@Entity 
    public class Reservation { 

     public static final long NOT_FOUND = -1L; 

     @Id 
     @GeneratedValue(strategy = GenerationType.IDENTITY) 
     public Long id; 

     @OneToMany(mappedBy = "reservation", cascade = CascadeType.ALL, orphanRemoval = true) 
     public List<RoomReservation> roomReservations = new ArrayList<>(); 
} 

模型2:客房預訂:

public class RoomReservation extends{ 

     @Id 
     @GeneratedValue(strategy = GenerationType.IDENTITY) 
     public Long id; 

     @JsonIgnore 
     @ManyToOne(fetch = FetchType.LAZY) 
     @JoinColumn(name = "RESERVATION_ID") 
     public Reservation reservation; 

     @OneToMany(mappedBy = "roomReservation", cascade = CascadeType.ALL, orphanRemoval = true) 
     public List<GuestDetails> guestDetails = new ArrayList<>(); 
    } 

模型3:來賓詳細介紹:

public class GuestDetails { 
    @Id 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    public Long id; 

    public Long guestId; 

    @JsonIgnore 
    @ManyToOne(fetch = FetchType.LAZY) 
    @JoinColumn(name = "ROOM_RESERVATION_ID") 
    public RoomReservation roomReservation; 

    public Boolean isPrimary; 

    @Transient 
    public Guest guest; 

} 

這三個之間的關係爲:

預訂 - 資助到許多關於RESERVATION_ID - >客房預訂 - 資助到許多關於ROOM_RESERVATION_ID - >客戶詳細

我收到預約對象,並試圖更新客人信息,我收到以下錯誤:

org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : com.model.GuestDetails.roomReservation -> com.model.RoomReservation 
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1760) 
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1677) 
    at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:82) 
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517) 
... 73 common frames omitted 

我已經改變了的CascadeType爲ALL中常見的問題,建議仍然得到同樣的error.Please DONOT使其複製我試圖realated這類問題的解決方案都已經問

請讓我知道我在做什麼錯誤。由於

代碼通過改變GuestDetails保存預約對象:

Reservation existingReservation = reservationRepository.findOne(reservationId); 
Reservation reservation = reservationParser.createFromJson(reservationNode); 
existingReservation.roomReservations.forEach(roomReservation -> { 
        RoomReservation updatedRoomReservation = reservation.roomReservations.stream().filter(newRoomReservation -> Objects.equals(roomReservation.id, newRoomReservation.savedReservationId)).findFirst().orElse(null); 
        if(updatedRoomReservation != null){ 
         roomReservation.guestDetails = updatedRoomReservation.guestDetails; 
        } 
       }); 
reservationRepository.save(existingReservation); 
+1

請發佈實際上正在進行保存的代碼 - 您試圖保存什麼類的類型? – PaulNUK

+0

@PaulNUK我已經添加了代碼塊,我正在使用save.Please看看。 –

+0

@PaulNUK嗨,任何更新..? –

回答

1

GuestDetails - 添加所需的CasadeType:

@ManyToOne(fetch = FetchType.LAZY, cascade=CascadeType.ALL) 
@JoinColumn(name = "ROOM_RESERVATION_ID") 
public RoomReservation roomReservation; 

RoomReservation - 添加nedded CascadeType的:

@JsonIgnore 
@ManyToOne(fetch = FetchType.LAZY, cascade=CascadeType.AL) 
@JoinColumn(name = "RESERVATION_ID") 
public Reservation reservation; 

然後你需要使用for-each循環後/前堅持數據。取決於你safe() -Method。

Reservation reservation = reservationParser.createFromJson(reservationNode); 
entityManager.persist(reservation); 

然後安全起來。告訴我你的結果。也許直接工作而不更改/添加cascadetypes。

+0

我已經嘗試將CascadeType.ALL添加到訪客詳細信息,並且在循環之後持久化對象仍然收到相同的錯誤。 –

0

您可以保存從Json的得到保留。 JPA將更新具有相同id的行。

你得到的錯誤是因爲guestDetails仍具有向updatedRoomReservation參考。 如果你不想從JSON拯救整個預約,你必須確立正確的RoomReservation。

例如爲:

if(updatedRoomReservation != null){ 
    roomReservation.guestDetails = updatedRoomReservation.guestDetails; 
    guestDetails.forEach(guestDetail -> guestDetail.roomReservation = roomReservation); 
} 
0

如果你正在使用JPA 2.0然後默認取類型一對多是懶惰。如果在你的lambda之後,你的updatedRoomReservationnull(如你在orElse中設置的那樣),那麼existingReservation.roomReservation.guestDetails永遠不會被加載,並且將爲空。

因此,當你保存existingReservation,你會得到錯誤。

1
... save the transient instance before flushing : 
    com.model.GuestDetails.roomReservation -> com.model.RoomReservation 

清楚,RoomReservation包含在GuestDetails這種異常狀態,不存在於數據庫中(最有可能是idnull)。

一般,您可以通過解決這個例外:

  • 節能RoomReservation實體節約GuestDetails

  • 或作出之前cascade = CascadeType.ALL(或至少{CascadeType.MERGE, CascadeType.PERSIST})爲@ManyToOneGuestDetail-->RoomReservation

Bu t個第一,我有幾個點的覆蓋:

  • 不要在課堂上使用公共字段,這違反the encapsulation concept

  • 當你有一個雙向關聯,你可以設置關聯另一側的Setter方法。

對於你的情況,你應該改變RoomReservation類:

public class RoomReservation{ 

    //..... other lines of code 

    @OneToMany(mappedBy = "roomReservation", cascade = CascadeType.ALL, orphanRemoval = true) 
    private List<GuestDetails> guestDetails = new ArrayList<>(); 

    public void setGuestDetails(List<GuestDetails> guestDetails) { 

      this.guestDetails.clear(); 

      // Assuming that by passing null or empty arrays, means that you want to delete 
      // all GuestDetails from this RoomReservation entity 
      if (guestDetails == null || guestDetails.isEmpty()){ 
       return; 
      } 

      guestDetails.forEach(g -> g.setRoomReservation(this)); 
      this.guestDetails.addAll(guestDetails); 
    } 

    public List<GuestDetails> getGuestDetails() { 
     // Expose immutable collection to outside world 
     return Collections.unmodifiableList(guestDetails); 
    } 

    // You may add more methods to add/remove from [guestDetails] collection 
} 

保存預約:

Reservation existingReservation = reservationRepository.findOne(reservationId); 
Reservation reservation = reservationParser.createFromJson(reservationNode); 
existingReservation.roomReservations.forEach(roomReservation -> { 
        Optional<RoomReservation> updatedRoomReservation = reservation.roomReservations.stream().filter(newRoomReservation -> Objects.equals(roomReservation.id, newRoomReservation.savedReservationId)).findFirst(); 
        if(updatedRoomReservation.isPresent()){ 
         // roomReservation already exists in the database, so we don't need to save it or use `Cascade` property 
         roomReservation.setGuestDetails(updatedRoomReservation.get().getGuestDetails()); 
        } 
       }); 
reservationRepository.save(existingReservation); 

希望它能幫助!

相關問題