30

How can I map a Map in JPA without using Hibernate's classes?

hello_there_andy
  • 2,039
  • 2
  • 21
  • 51
Rafa de Castro
  • 2,474
  • 1
  • 24
  • 44

4 Answers4

37

Although answer given by Subhendu Mahanta is correct. But @CollectionOfElements is deprecated. You can use @ElementCollection instead:

@ElementCollection
@JoinTable(name="ATTRIBUTE_VALUE_RANGE", joinColumns=@JoinColumn(name="ID"))
@MapKeyColumn (name="RANGE_ID")
@Column(name="VALUE")
private Map<String, String> attributeValueRange = new HashMap<String, String>();

There is no need to create a separate Entity class for the Map field. It will be done automatically.

Jatin Sehgal
  • 956
  • 2
  • 17
  • 37
17

Does not the following work for you?

@ManyToMany(cascade = CascadeType.ALL)
Map<String,EntityType> entitytMap = new HashMap<String, EntityType>();

EntityType could be any entity type, including a String.

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
Chris K
  • 11,996
  • 7
  • 37
  • 65
  • 17
    I'm a little confused. The question was about mapping a Map, but the "best answer" is about a Map. Do i miss something? – whiskeysierra Jan 10 '10 at 14:15
  • 11
    EntityType could be any entity type, including a String. – Chris K Jan 16 '10 at 06:41
  • 3
    How many tables does this generate? Is there (1) one for the original class, (2) a join table (with keys for the original class and the entity type) and (3) another table for the EntityType (in the given scenario, a table with just the join table key and the mapped string)? This may be a lot of overhead, depending on the Strings saved... – RobertG Dec 18 '12 at 09:19
  • 1
    For a solution without a join table, confer the example in http://stackoverflow.com/a/6247360/1143126 - it is buggy until hibernate 4.1.6, though. – RobertG Dec 18 '12 at 09:55
  • This shouldn't generate any join tables - he's not asking to join maps, but a Map. Not a Map of Maps. – Chris K Dec 19 '12 at 11:06
  • 15
    @ChrisKaminski You are wrong for saying that String is entity type because it does not have Id. You know what I mean and you may know what is called entity. – Ramsharan Jul 24 '13 at 01:35
  • 4
    For String,String mapping this will not work along. Suggesting to deselect as best answer. – Dimuthu May 21 '15 at 10:32
  • @ChrisKaminski As has already been mentioned : `String` is not a valid `Entity` – specializt Nov 11 '15 at 06:11
10

Suppose I have an entity named Book which is having a Map of chapters:

import java.io.Serializable;
import java.util.Map;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;    
import org.hibernate.annotations.CollectionOfElements;
import org.hibernate.annotations.MapKey;
@Entity
public class Book implements Serializable{
@Column(name="BOOK_ID")
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long bookId;    

@CollectionOfElements(targetElement=java.lang.String.class)
@JoinTable(name="BOOK_CHAPTER",
        joinColumns=@JoinColumn(name="BOOK_ID"))
@MapKey (columns=@Column(name="CHAPTER_KEY"))
@Column(name="CHAPTER")
private Map<String,String> chapters;
public Long getBookId() {
    return bookId;
}
public void setBookId(Long bookId) {
    this.bookId = bookId;
}
public Map<String,String> getChapters() {
    return chapters;
}
public void setChapters(Map<String,String> chapters) {
    this.chapters = chapters;
}               

}

It works for me.

Subhendu Mahanta
  • 961
  • 1
  • 18
  • 44
  • +1. And what if i want to retrieve only the chapter 3 of all of these books? I have a similar question: http://stackoverflow.com/questions/12952625/jpa-category-language-relationship – ianaz Oct 18 '12 at 15:57
  • 1
    @ianaz `select c from Book b join b.chapters c where key(c) = '3'` – Steve Ebersole Nov 16 '12 at 15:51
  • 3
    Unfortunately, this requires hibernate-specific annotations. The question was for a solution without. – RobertG Dec 18 '12 at 09:23
4

A working example:

@ElementCollection(fetch=FetchType.EAGER)
@CollectionTable(name = "TABLENAME")
@MapKeyColumn(name = "KEY")
@Column(name = "VALUE")
public Map<String, String> getMap() {
    return _map;
}
Yassin Hajaj
  • 21,337
  • 9
  • 51
  • 89
Francesco Taioli
  • 2,687
  • 1
  • 19
  • 34
  • for a many-to-many relationship, you'd also need `joinColumns = @JoinColumn(name="referencing_column")` within @CollectionTable and `@MapKeyJoinColumn(name="referencing_column_other_table")` – phil294 Feb 03 '17 at 00:55