What are the hibernate annotations used to persist a Map with an enumerated type as a key?
- by Jason Novak
I am having trouble getting the right hibernate annotations to use on a Map with an enumerated class as a key. Here is a simplified (and extremely contrived) example.
public class Thing {
public String id;
public Letter startLetter;
public Map<Letter,Double> letterCounts = new HashMap<Letter, Double>();
}
public enum Letter {
A,
B,
C,
D
}
Here are my current annotations on Thing
@Entity
public class Thing {
@Id
public String id;
@Enumerated(EnumType.STRING)
public Letter startLetter;
@CollectionOfElements
@JoinTable(name = "Thing_letterFrequencies", joinColumns = @JoinColumn(name = "thingId"))
@MapKey(columns = @Column(name = "letter", nullable = false))
@Column(name = "count")
public Map<Letter,Double> letterCounts = new HashMap<Letter, Double>();
}
Hibernate generates the following DDL to create the tables for my MySql database
create table Thing (id varchar(255) not null, startLetter varchar(255), primary key (id)) type=InnoDB;
create table Thing_letterFrequencies (thingId varchar(255) not null, count double precision, letter tinyblob not null, primary key (thingId, letter)) type=InnoDB;
Notice that hibernate tries to define letter (my map key) as a tinyblob, however it defines startLetter as a varchar(255) even though both are of the enumerated type Letter. When I try to create the tables I see the following error
BLOB/TEXT column 'letter' used in key specification without a key length
I googled this error and it appears that MySql has issues when you try to make a tinyblob column part of a primary key, which is what hibernate needs to do with the Thing_letterFrequencies table. So I would rather have letter mapped to a varchar(255) the way startLetter is.
Unfortunately, I've been fussing with the MapKey annotation for a while now and haven't been able to make this work. I've also tried @MapKeyManyToMany(targetEntity=Product.class) without success. Can anyone tell me what are the correct annotations for my letterCounts map so that hibernate will treat the letterCounts map key the same way it does startLetter?