views:

379

answers:

3

Using annotations how do you map a field in an entity which is a "Map" (Hashtable) of String to a given object? The object is annotated and instances of it are already stored in the hibernate databse.

I've found the syntax for definging a map with a simple key and value as such:

<class name="Foo" table="foo">
    ...
    <map role="ages">
         <key column="id"/>
         <index column="name" type="string"/>
         <element column="age" type="string"/>
     </map>
 </class>

And oddly with an entity as the key and a simple type as the value like so:

<class name="Foo" table="foo">
    ...
  <map role="ages">
    <key column="id"/>
    <index-many-to-many column="person_id" 
         class="Person"/>
    <element column="age" type="string"/>
  </map>
</class>
<class name="Person" table="person">
    ...
    <property name="name" column="name" 
         type="string"/>
</class>

But I don't see how to do this for a simple key to element mapping, and I don't see how to do this using annotations.

+1  A: 

You should probably use a UserType or UserCollectionType. Or, you can use a custom tupleizer.

see hibernate core documentation for the concepts and hibernate annotations documentation for the equivalent annotation approach.

Let me know if that isn't what you are asking for.

Jeff Walker
I hate to sound like an idiot but I've been looking at those very same two pages on and off all day and I don't seem to get it. I've been looking at this style:<map role="ages"> <key column="id"/> <index column="name" type="string"/> <element column="age" type="string"/></map>Which seems to be the kind of thing I need I just don't understand how to do it as annotation. I also don't know how I'd do it if the element wasn't a string.Do I have the wrong end of the stick.
Omar Kooheji
Yes, I think you really want a UserType, because all of the other things discussed here (I believe) create another table to store the map in.Look at the UserType interface and you will see that there are only a few methods to implement. Basically you tell hibernate, given a ResultSet, how to put it into the java type and vice-versa.
Jeff Walker
+1  A: 
@CollectionOfElements(fetch = FetchType.LAZY)
@JoinTable(name = "JOINTABLE_NAME",
    joinColumns = @JoinColumn(name = "id"))
@MapKey(columns = @Column(name = "name"))
@Column(name = "age")
private Map<String, String> ages = new HashMap<String, String>();
Willi
That is the kind of thing I am looking for however how would I do it if the key was a string as in the example and the value was another object?
Omar Kooheji
That looks similar to the annotation for mapping an Enum.
James P.
@Omar: Should be as simple as replacing "String" with the entity type of your choice. You might need to remove @Column(name = "age") and add something like inverseJoinColumns=@JoinColumn(name="fk_ik") to the @JoinTable-annotation. Not sure though.
Willi
I tried something like that for persisting an ArrayList (The inverse join column thing) but ran into some trouble with my DBUnit tests they couldn't drop the tables to repopulate them because there was a circular dependancy between the two tables.
Omar Kooheji
Did u try to persist a single arraylist as a value of a map?
Willi
+1  A: 

You could simply use the JPA annotation @MapKey (note that the JPA annotation is different from the Hibernate one, the Hibernate @MapKey maps a database column holding the map key, while the JPA's annotation maps the property to be used as the map's key).

@javax.persistence.OneToMany(cascade = CascadeType.ALL)
@javax.persistence.MapKey(name = "name")
private Map<String, Person> nameToPerson = new HashMap<String, Person>();
Pascal Thivent
Thanks I'll try this. What kind of databse schema does this reflect? I'm using DB unit and want to be able to populate the dataset using XML. Does this use a join table? if so can you specify what the table is called and what are the columns of the join table?
Omar Kooheji
@Omar It creates a join table (FOO_PERSON by default). You can control the name using `@javax.persistence.JoinTable`. Not sure about the columns.
Pascal Thivent