спящий режим «многие ко многим» с дополнительными полями: не удается найти объект с идентификатором

#java #database #hibernate #jpa

Вопрос:

Я застрял на проблеме, связанной с запросами jpa n…m в режиме гибернации. Моя настройка выглядит следующим образом:

 ChatRoom <--> Participant
 

с оговоркой, что участник картографической таблицы RoomParticipant имеет дополнительное активное поле:

 Room -> RoomParticipant <- Participant
id      id                 id
name    roomId             name
...     participantId      ...
        active
 

Пройдя несколько уроков и прочитав множество предложений по исправлению ошибок, я застрял с этой настройкой (с использованием Ломбока).:

 @Entity
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
@EqualsAndHashCode
@Table(name = "rooms")
public class Room {

  @Id
  @GeneratedValue(generator = "uuid")
  @GenericGenerator(name = "uuid", strategy = "uuid")
  private String id;

  @OneToMany(mappedBy = "room")
  private List<RoomParticipant> roomParticipants = new ArrayList<RoomParticipant>();

  public void addParticipant(Participant participant) {
    RoomParticipant roomParticipant = new RoomParticipant(this, participant);
    roomParticipants.add(roomParticipant);
    participant.getRooms().add(roomParticipant);
  }
}

// class annotations omitted
public class Participant {  
  @Id
  private String id;

  @Column
  private String name;

  @OneToMany(mappedBy = "participant", cascade = CascadeType.ALL, orphanRemoval = false)
  @JsonIgnore
  private List<RoomParticipant> rooms = new ArrayList<RoomParticipant>();
}

// class annotations omitted
public class RoomParticipant {
  @EmbeddedId
  @JsonIgnore
  private RoomParticipantPK id;

  @ManyToOne (fetch = FetchType.LAZY)
  @MapsId("roomId")
  @JsonIgnore
  private Room room;

  @ManyToOne (fetch = FetchType.LAZY)
  @MapsId("participantId")
  private Participant participant;

  @Column
  private boolean active;

  public RoomParticipant(Room room, Participant participant) {
    this.room = room;
    this.participant = participant;
    this.id = new RoomParticipantPK(room.getId(), participant.getId());
    this.active = true;
  }
}


@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
@Embeddable
public class RoomParticipantPK implements Serializable {
  @Column(name="room_id")
  private String roomId;

  @Column(name="participant_id")
  private String participantId;
}
 

Аннотации классов все одинаковы, за исключением участников комнаты.
Теперь с этим у меня есть два вызова функций: один открывает новую комнату, этот работает!

   public Room createRoom(String title, String userId, String username) {
     Participant participant = participantRepository.findById(userId).orElse(createParticipant(userId, username));
     Room room = new Room();
     room.setTitle(title);
     room.addParticipant(participant);
     room.setArchived(false); 
     return chatRoomRepository.save(room);
   }
 

после вызова этой функции была создана новая комната, был создан новый участник, таблица room_participant была заполнена правильно.

Но теперь я пытаюсь объединить комнату со следующей функцией:

   public Room joinRoom(String roomId, String sessionId, String username) {
    Participant participant = participantRepository.findById(sessionId).orElse(createParticipant(sessionId, username));
    Room room = chatRoomRepository.findById(roomId).orElseThrow(() -> new InvalidRoomException(roomId));
    room.addParticipant(participant);
    return chatRoomRepository.save(room);
  }
 

и это НЕ работает из-за следующей ошибки:

javax.persistence.EntityNotFoundException: Unable to find ...chatservice.model.entities.RoomParticipant with id ...chatservice.model.entities.RoomParticipantPK@cc9e297f

обе функции вызывают createParticipant, который является следующим:

   private Participant createParticipant(String userId, String username) {
     return participantRepository.save(new Participant(userId, username, new  ArrayList<RoomParticipant>()));
   }
 

Репозитории являются однострочными, расширяющими JpaRepository

 public interface ChatRoomRepository extends JpaRepository<Room, String> {}
public interface ParticipantRepository extends JpaRepository<Participant, String> {}
 

Комментарии:

1. Внедрите toString в свой RoomParticipantPK и посмотрите, какого идентификатора не хватает.

2. спасибо, теперь сообщение стало немного яснее: javax.persistence.EntityNotFoundException: Unable to find com.syncpilot.chatservice.model.entities.RoomParticipant with id 2c9d90817bcaa8db017bcaa9223a0000 P-ID2 (отправка в http://localhost:8091/chatservice/v1/http/room/2c9d90817bcaa8db017bcaa9223a0000/join следующем теле: displayName: 'name' participantId: 'P-ID2' . В моей базе данных у меня есть участник с P-ID2 в таблице участников. Также 2c9d90817bcaa8db017bcaa9223a0000 в номерах есть номер с удостоверением личности. Это просто не добавляет запись в room_participant

3. Я также систематизировал напечатанные идентификаторы комнаты и участника в моей строке ввода — ни один из них не отсутствует, строка вызывается только один раз, и оба идентификатора установлены

Ответ №1:

Вы не сохраняете свою комнату, в которой она создана Room.addParticipant .

Чтобы избежать дополнительной реализации RoomParticipantRepsitory , просто измените аннотацию с Room.roomParticipants

  @OneToMany(mappedBy = "room")
 

Для

  @OneToMany(mappedBy = "room", cascade = CascadeType.ALL, orphanRemoval = true)