views:

149

answers:

1

I think this is pretty much the simplest case for mapping a Map (that is, an associative array) of entities.

@Entity
@AccessType("field")
class Member {
    @Id
    protected long id;

    @OneToMany(cascade = CascadeType.ALL, fetch=FetchType.LAZY)
    @MapKey(name = "name")
    private Map<String, Preferences> preferences
             = new HashMap<String, Preferences>(); 
}

@Entity
@AccessType("field")
class Preferences {
    @ManyToOne Member member;
    @Column String name;
    @Column String value;
}

This looks like it should work, and it does, in HSQL. In MySQL, there are two problems: First, it insists that there be a table called Members_Preferences, as if this were a many-to-many relationship.

Second, it just doesn't work: since it never populates Members_Preferences, it never retrieves the Preferences.

[My theory is, since I only use HSQL in memory-mode, it automatically creates Members_Preferences and never really has to retrieve the preferences map. In any case, either Hibernate has a huge bug in it or I'm doing something wrong.]

+1  A: 

And of course, I sweat the problem for hours, post it here, and a minute later...

Anyway, the answer is the mappedBy element of the @OneToMany annotation:

@OneToMany(cascade = CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="member")
@MapKey(name = "name")
private Map<String, Preferences> preferences
         = new HashMap<String, Preferences>(); 

Which makes a certain sense: which field in the Many entity points back to the One entity? Even allowing that looking for a matching @ManyToOne field was too error prone, I think that what they did do (assuming the existence of a mapping table) makes even worse.

Malvolio