I look at various ways to annotate maps using Hibernate 4.1.9 and JPA annotations.
If I want to save a map where the key is an attribute of an entity value, then the inscription looks like this:
@OneToMany(mappedBy = "deptById", targetEntity = com.demo.impls.Employee.class) @MapKey(name = "entityId") private Map<Long, Employee> employeesById;
Please note that the above mark does not create a connection table, but Map is returned through the query at runtime, therefore the map is dynamic, and you do not need to add an element to the map in Java so that they return upon request.
Now I want the contents of the Map to reflect what the application added to the Map, rather than performing a dynamic request.
There are 4 varieties of the map that I want to save
private Map<String, String> map0; private Map<String, Entity> map1; private Map<Entity, String> map2; private Map<Entity, Entity> map3;
In these cases, there is no NO relationship between the key and the value, and there is no relation to the holding Entity. I should be able to specify the join table name well, as the column names for the key and value.
I tried the following
@Entity public class Department { @ElementCollection @CollectionTable(name = "TEST_MAP0") @Column(name="value") @MapKeyColumn(name="Key") private Map<String, String> map0; @ElementCollection(targetClass = com.demo.bb.impls.Employee.class) @CollectionTable(name = "TEST_MAP1") @Column(name="value") @MapKeyColumn(name="Key") private Map<String, Employee> map1; @ElementCollection @MapKeyClass(value = com.demo.bb.impls.Employee.class) @CollectionTable(name = "TEST_MAP2") @Column(name="value") @MapKeyColumn(name="Key") private Map<Employee, String> map2; @ElementCollection(targetClass = com.demo.bb.impls.ParkingSpace.class) @MapKeyClass(value = com.demo.bb.impls.Employee.class) @CollectionTable(name = "TEST_MAP3") @Column(name="value") @MapKeyColumn(name="Key") private Map<Employee, ParkingSpace> map3;
Case 0 The card works fine, and in the generated connection table there are columns DEPARTMENT, VALUE, KEY
The other three cases work the same way you can store data in tables, and in Java, query tables with corresponding keys / values ββand return the expected results - that is, handle storing objects using @ElementCollection
But the column name is overridden by @Column (name = "value") and @MapKeyColumn (name = "key") are ignored when the key or value is Entity.
I tried using @ManyToMany annotations as follows
@ManyToMany(targetEntity = com.demo.bb.impls.Employee.class) @JoinTable(name = "TEST_MAP1_B") @Column(name="value") @MapKeyColumn(name="Key") private Map<String, Employee> map1_B; @ManyToMany(targetEntity = com.demo.bb.impls.ParkingSpace.class) @MapKeyClass(value = com.demo.bb.impls.Employee.class) @JoinTable(name = "TEST_MAP3_B") @Column(name="value") @MapKeyColumn(name="Key") private Map<Employee, ParkingSpace> map3_B;
But overrides of key column names and values ββare ignored. Does anyone know a way to enforce these column name overrides.
Thanks in advance...
UPDATE .... Looking at the answer from @wypieprz, I think I know the correct annotation so that you can specify the column names for the value and key when the map is bound by a base with an entity value.
Using the following
@ManyToMany(targetEntity = com.demo.bb.impls.Employee.class) @JoinTable(name = "TEST_MAP1", inverseJoinColumns=@ JoinColumn(name="VALUE")) @MapKeyColumn(name="KEY") private Map<String, Employee> map1;
Using inverseJoinColumn, I can specify the column name of the value.
But if the key is Entity, I did not find a way to specify the key column name. According to doc @MapKeyColumn "indicates a mapping for the key column of the map whose map key is the base type"
I'm also not sure about the usage comments when the key is Entity and the value is basic. Using ManyToMany just does not work, and I think that I may have to use ElementCollection, but again I can not find a way to specify the column name.
UPDATE 2 ... Thanks to Peter Haliki for the solution.
In conclusion, to name all 3 columns in each of the cases, you need to do something like this.
@ElementCollection @CollectionTable(name = "TEST_MAP0", joinColumns = @JoinColumn(name = "DEPARTMENT")) @Column(name = "value") @MapKeyColumn(name = "key") private Map<String, String> map0; @ManyToMany(targetEntity = com.hibernate.elephants.Employee.class) @JoinTable(name = "TEST_MAP1", joinColumns = @JoinColumn(name = "DEPARTMENT"), inverseJoinColumns = @JoinColumn(name = "value")) @MapKeyColumn(name = "key") private Map<String, Employee> map1; @ElementCollection @CollectionTable(name = "TEST_MAP2", joinColumns = @JoinColumn(name = "DEPARTMENT")) @MapKeyClass(value = com.hibernate.elephants.Employee.class) @MapKeyJoinColumn(name = "key") @Column(name = "value") private Map<Employee, String> map2; @ManyToMany(targetEntity = com.hibernate.elephants.ParkingSpace.class) @JoinTable(name = "TEST_MAP3", joinColumns = @JoinColumn(name = "DEPARTMENT"), inverseJoinColumns = @JoinColumn(name = "value")) @MapKeyClass(value = com.hibernate.elephants.Employee.class) @MapKeyJoinColumn(name="key") private Map<Employee, com.hibernate.elephants.ParkingSpace> map3;
Note that two cases are indicated as an ElementCollection, but two cases where this value is another object must use ManyToMany.