#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_participant3. Я также систематизировал напечатанные идентификаторы комнаты и участника в моей строке ввода — ни один из них не отсутствует, строка вызывается только один раз, и оба идентификатора установлены
Ответ №1:
Вы не сохраняете свою комнату, в которой она создана Room.addParticipant
.
Чтобы избежать дополнительной реализации RoomParticipantRepsitory
, просто измените аннотацию с Room.roomParticipants
@OneToMany(mappedBy = "room")
Для
@OneToMany(mappedBy = "room", cascade = CascadeType.ALL, orphanRemoval = true)