2017-10-20 159 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); 

希望它能帮助!

相关问题