Mapping maps in Hibernate using JPA2

287 views Asked by At

I am trying to map a java.util.Map with Hibernate, but can't seem to get it right. I am using Hibernate 4.2.8.Final and hibernate3-maven-plugin 2.2. Originally I wanted to have a map keyed by an enum-value, with an entity as a value, but no matter what I tried the database definition didn't come out right with hbm2ddl. So, I resorted into trying a simple example from my JPA2 book, mapping a Map<String, String. This is how I did that (I am only using JPA annotations (javax.annotation)):

@ElementCollection
@CollectionTable(name = "coll_table")
@MapKeyColumn(name = "something")
@Column(name = "somethingElse")
public Map<String, String> getSomething() {
    return something;
}

When trying to do hbm2ddl, it fails with:

Execution default-cli of goal org.codehaus.mojo:hibernate3-maven-plugin:2.2:hbm2ddl failed: Could not determine type for: java.util.Map, at table: SomeTable, for columns: [org.hibernate.mapping.Column(somethingElse)] -> [Help 1]

So, I added targetClass=String.classto the @ElementCollection annotation (even though it shouldn't be necessary.) It does not help.

But, back to the problem I was trying to solve in the first place, mapping with an enum key and an entity value.

This mapping (where LetterType is an enum, Letter is an entity):

@OneToMany
@MapKeyEnumerated(EnumType.ORDINAL)
public Map<LetterType, Letter> getLetters() {
    return letter;
}

yields the following SQL:

create table Application_Letter (
    Application_Id int not null,
    letter_id int not null,
    mapkey varbinary(255) null,
    primary key (Application_Id, mapkey),
    unique (letter_id)
);

Not a shocking result, given my minimal mapping (a bit strange that the key that was defined as ORDINAL is supposed to be store in a varbinary(255) column thought.) But it's when I try to expand with more options that I run into problems, I can't seem to make the mapkey column get any other name or type, no matter what I try!

This mapping (Letter has an attribute type, of type LetterType):

@OneToMany
@JoinTable(name = "application_letter",
           joinColumns = @JoinColumn(name = "app_id"),
           inverseJoinColumns = @JoinColumn(name = "letter_id"))
@MapKey(name = "type")
@MapKeyEnumerated(EnumType.STRING)
public Map<LetterType, Letter> getLetters() {
    return letters;
}

Yields:

create table application_letter (
    app_id int not null,
    letter_id int not null,
    primary key (app_id, letter_id),
    unique (letter_id)
);

So it's listening to some of my annotations, but still it gets the key part wrong (looks like it thinks that the id attribute of Letter is the key, and not the type attribute as I specified.) This led me on to believe that there is something wrong with using enum-values as keys, so I tried this:

@OneToMany
@JoinTable(name = "application_letter_string",
           joinColumns = @JoinColumn(name = "app_id"),
           inverseJoinColumns = @JoinColumn(name = "letter_id"))
@MapKeyColumn(name = "letterType")
public Map<String, Letter> getLettersString() {
    return lettersString;
}

Now I'm using a String-typed key, and naming it explicitly, this has to work. But no, the result is:

create table application_letter_string (
    app_id int not null,
    letter_id int not null,
    mapkey varchar(255) null,
    primary key (app_id, mapkey),
    unique (letter_id)
);

At least it's noticed that the key is a String, and made the key-column a varchar, but the name I specified is nowhere to be seen.

This leads me to my final question: Am I doing something wrong here, or does Hibernate's way of dealing with Maps simply not work? (Can't create a Map between primitives, can't create a Primitive->Entity map, can't create an enum->Entity map, can't create a entityMember->Entity map, not many options left.)

0

There are 0 answers