Home > Blockchain >  hibernate many-to-many with additional fields: unable to find entity with id
hibernate many-to-many with additional fields: unable to find entity with id

Time:09-17

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)
  • Related