Thomas Chen
Thomas Chen

Reputation: 37

How to Annotate OneToMany association between HashMap Key and another Class (Java/JPA/Hibernate)

Here are the two classes in question (Simplified to only relevant parts):

Message Class (ManyToOne relationship with Board Class)

@Entity
@Table(name = "messages")
public class Message {

/**
 * Unique identifier for message.
 */
@Id
private UUID id;

@ManyToOne
@JoinColumn(name = "id")
private Board owner;

Board Class (OneToMany Relationship with Message class)

@Entity
@Table(name = "boards")
public class Board {

/**
 * Unique identifier for task.
 */
@Id
private UUID id;

/**
 * Hashmap of all messages currently on Board
 */
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@MapKey(name = "owner")
private HashMap<Message, Integer> messageBoard;

Using spring-boot-starter-data-jpa version 2.1.0.RELEASE

I am attempting to map many Messages to a single Board, and want to cascade and delete all messages in a Board when a Board is deleted. I require the key of the HashMap to be the Messages in the board, and the Integer value of the HashMap has no relationship with the Message class's fields. Welcome to alternatives if this is not possible.

Upvotes: 1

Views: 3623

Answers (1)

Ken Chan
Ken Chan

Reputation: 90447

You cannot do that as the related many entity (i.e Message) is required to be the Map value. You need to do it the other way round which map the key as the message ID and the value as the message instance :

@Entity
@Table(name = "boards")
public class Board {


  @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true ,  mappedBy = "owner")
  @MapKey(name = "id")
  private Map<UUID, Message> messages = new HashMap<>();

}

Also , please note that I make two changes of your mapping above:

  1. Use Map rather than HashMap when declaring the Message type.Otherwise , it will have the following error:

    Caused by: org.hibernate.AnnotationException: java.util.HashMap collection type not supported for property`

  2. Use mappedBy to have a bi-directional one-to-many mapping and let the "many" side to manage the relationship for better performance.(Refer to this)


I want to cascade and delete all messages in a Board when a Board is deleted.

Actually you don't need to map the Message as a Map in order to do that. You can also achieve it by simply mapping it as a List. The codes to do it is somethings like below which you can see that you do not need to manipulate the message ID. All you need is get the board ID that you want to delete.

@Transactional
public void deleteBoard(String boardId){
  Board board = entityManager.getReference(Board.class, boardId);
  entityManager.remove(board);
}

Upvotes: 2

Related Questions