I'm stuck on an issue regarding hibernate jpa n...m requests. My setup looks like the following:
ChatRoom <--> Participant
with the caviat that the mapping table RoomParticipant has an additional active field:
Room -> RoomParticipant <- Participant
id id id
name roomId name
... participantId ...
active
After doing some tutorials and reading a lot of bug fix suggestions, I'm stuck with this setup (utilizing Lombok):
@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;
}
The class annotations are all the same except RoomParticipant. Now, with this i have two function calls: one opens up a new room, This one works!
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);
}
after calling this function, a new room has been created, a new Participant has been created the room_participant table has been filled correctly.
But now I'm trying to join a room with the following function:
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);
}
and this does NOT work due to the following error:
javax.persistence.EntityNotFoundException: Unable to find ...chatservice.model.entities.RoomParticipant with id ...chatservice.model.entities.RoomParticipantPK@cc9e297f
both functions call createParticipant which is this:
private Participant createParticipant(String userId, String username) {
return participantRepository.save(new Participant(userId, username, new ArrayList<RoomParticipant>()));
}
The repositories are one-liner extending JpaRepository
public interface ChatRoomRepository extends JpaRepository<Room, String> {}
public interface ParticipantRepository extends JpaRepository<Participant, String> {}
CodePudding user response:
You don't save your RoomParticipant which is created in Room.addParticipant
.
To avoid implementing an extra RoomParticipantRepsitory
just change annotation in Room.roomParticipants
from
@OneToMany(mappedBy = "room")
to
@OneToMany(mappedBy = "room", cascade = CascadeType.ALL, orphanRemoval = true)