2017-10-20 15 views
7

Tôi có Dưới 3 mô hình:đối tượng tham chiếu một thể hiện thoáng qua chưa được lưu - lưu dụ thoáng qua trước khi xả nước: Mùa xuân dữ liệu JPA

Mẫu 1: Đặt

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

Mô hình 2: Phòng Reservation:

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<>(); 
    } 

Mô hình 3: Chi tiết khách:

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; 

} 

Mối quan hệ giữa ba như:

Reservation --One để Nhiều người trên RESERVATION_ID -> Đặt Phòng --One để Nhiều người trên ROOM_RESERVATION_ID -> Khách Chi tiết

Tôi nhận được đối tượng đặt phòng và cố gắng để cập nhật thông tin của khách tôi nhận được lỗi sau:

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 

tôi đã thay đổi cascadeType cho TẤT CẢ như đề xuất trong câu hỏi phổ biến vẫn nhận được error.Please cùng donot làm cho nó trùng lặp vì tôi đã thử tất cả các giải pháp được thực hiện cho loại câu hỏi này đã được hỏi

Hãy cho tôi biết tôi đang làm gì sai. Cảm ơn

Mã để tiết kiệm Reservation Object bằng cách thay đổi 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

Vui lòng đăng mã thực sự đang thực hiện lưu - loại bạn đang cố gắng lưu loại lớp nào? – PaulNUK

+0

@PaulNUK Tôi đã thêm khối mã mà tôi đang sử dụng để lưu.Xin vui lòng xem. –

+0

@PaulNUK Xin chào, mọi cập nhật ..? –

Trả lời

1

GuestDetails - thêm CasadeType cần thiết:

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

RoomReservation - thêm CascadeType nedded:

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

Và sau đó bạn cần phải lưu giữ dữ liệu trước/sau khi sử dụng vòng lặp for-each. Phụ thuộc vào bạn safe() -Phương pháp.

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

Và sau đó an toàn sau đó. Hãy cho tôi biết kết quả của bạn. Có thể trực tiếp làm việc mà không thay đổi/thêm các cascadetypes.

+0

Tôi đã thử thêm cascadeType.ALL vào Chi tiết Khách và đối tượng bền bỉ sau khi vòng lặp vẫn nhận được lỗi tương tự. –

0

Bạn có thể lưu đặt chỗ bạn nhận được từ Json. JPA sẽ cập nhật các hàng có cùng id.

Lỗi bạn nhận được là do guestDetails vẫn là tham chiếu đến updatedRoomReservation. Nếu bạn không muốn lưu toàn bộ đặt phòng từ json, bạn phải đặt RoomReservation phù hợp.

ví dụ .:

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

Nếu bạn đang sử dụng JPA 2,0 thì giá trị mặc định lấy kiểu cho OneToMany là lười.Nếu sau lambda của bạn, số updatedRoomReservation của bạn là null (như bạn đã đặt bằng orElse) thì existingReservation.roomReservation.guestDetails sẽ không bao giờ được tải và sẽ bị vô hiệu.

Do đó, khi bạn lưu existingReservation, bạn sẽ gặp lỗi.

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

ngoại lệ này bang rõ ràng RoomReservation chứa trong GuestDetails, không tồn tại trong cơ sở dữ liệu (và nhiều khả năng đó là idnull).

Nói chung, bạn có thể giải quyết ngoại lệ này bằng cách:

  • Saving RoomReservation thực thể trước khi GuestDetails tiết kiệm

  • Hoặc làm cascade = CascadeType.ALL (hoặc ít nhất {CascadeType.MERGE, CascadeType.PERSIST}) cho @ManyToOneGuestDetail-->RoomReservation

Bu trước tiên, tôi có một vài điểm để trang trải:

  • Không sử dụng các trường công khai trong lớp học của bạn, vi phạm the encapsulation concept.

  • Trong khi bạn có liên kết hai chiều, bạn có thể đặt phía bên kia của liên kết trong các phương thức Setter của bạn.

Đối với trường hợp của bạn, bạn nên thay đổi RoomReservation lớp:

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 
} 

Cứu Reservation:

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); 

Hy vọng nó sẽ giúp!

Các vấn đề liên quan