using Hibernate Core 4.1.7, JPA annotations, java 1.7
Easy to fine are examples about Map<String, Entity> reading Hibernate doc on collections, or Map<String, String> here (stackoverflow).
Hard to find are examples on Map<String, Set<String>>
(or even Map<String, Map<String, String>> just for curiosity about daisy chaning) why I ask this question here.
All I want is to save entities (accounts) containing named, multi-valued properties (=account attributes).
I have all working with 3 entity types: Account -> @OneToMany -> AccountAttribute -> @OneToMany -> AccountAttributeValue
But wrapping native Java types with my own Classes seems a bit silly to me. Cloning the Map<String, String> example I would like to have something like
@Entity
public class Account {
@Id @GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="key")
private Long key;
@ElementCollection(fetch=FetchType.EAGER)
@JoinTable(name = "Attribute",
joinColumns = @JoinColumn(name = "fkAccount"))
@MapKeyColumn(name = "name")
// next line is working for Map<String, String>, but not here!
@Column(name = "value")
private Map<String, Set<String>> attributes = new HashMap<String, Set<String>>();
// ... omitting: constructor, getters, setters, toString()
}
Which gives me
Initial SessionFactory creation failed: org.hibernate.MappingException: Could not determine type for: java.util.Set, at table: Attribute, for columns:[org.hibernate.mapping.Column(attributes)]
As DB layout I have created 2 Tables.
- Table Account
just having a key to point foreign key to
- Table Attribute
containing named value in each line.
E.g. for multivalued attributes I thought of it containing 2 lines with same fkAccount
and name
but different value
- yes, I could have normalized even more, but I want to read my data in acceptable time :-)
CREATE TABLE IF NOT EXISTS `foo`.`Account` (
`key` INT NOT NULL AUTO_INCREMENT ,
...
CREATE TABLE IF NOT EXISTS `foo`.`Attribute` (
`fkAccount` INT NOT NULL ,
`name` VARCHAR(45) NOT NULL ,
`value` VARCHAR(45) NOT NULL
...
Any hints or alternate DB layout proposals appreciated.
EDIT - SOLVED
Solution from Tom (as far as I understood) working for me
Thanky you guys, what an experience, solution in 1 day!
The table layout just mentioned above in my question works now with this classes.
@Entity
public class Account {
/* ... omitting "key", see as above */
/* NEW: now @CollectionTable
replaces @JoinTable / @MapKeyColumn / @Column from above
*/
@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name="AccountAttribute",
joinColumns=@JoinColumn(name="fkAccount"))
private Set<AccountAttribute> attributes = null;
// ... omitting: constructor, getters, setters, toString()
}
and NEW
@Embeddable
public class AccountAttribute {
@Column(name="attributeName")
private String attributeName = null;
@Column(name="attributeValue")
private String attributeValue = null;
// ... omitting: constructor, getters, setters, toString()
}