As per Hibernate documentation, there are multiple annotations available if we want to use Map as an association between our entities. The doc says:
A
When you use a Map you always need to associate at least two entities. Let's say we have an Owner entity that relates to the Car entity (Car has a FK to Owner).
So, the Owner will have a Map of Car(s):
Map<X, Car>
@MapKeyThe @MapKey will give you the Car's property used to group a Car to its Owner. For instance, if we have a vin (Vehicle Identification Number) property in Car, we could use it as the carMap key:
@Entity
public class Owner {
@Id
private long id;
@OneToMany(mappedBy="owner")
@MapKey(name = "vin")
private Map<String, Car> carMap;
}
@Entity
public class Car {
@Id
private long id;
@ManyToOne
private Owner owner;
private String vin;
}
@MapKeyEnumeratedThe @MapKeyEnumerated will use an Enum from Car, like WheelDrive:
@Entity
public class Owner {
@Id
private long id;
@OneToMany(mappedBy="owner")
@MapKeyEnumerated(EnumType.STRING)
private Map<WheelDrive, Car> carMap;
}
@Entity
public class Car {
@Id
private long id;
@ManyToOne
private Owner owner;
@Column(name = "wheelDrive")
@Enumerated(EnumType.STRING)
private WheelDrive wheelDrive;
}
public enum WheelDrive {
2WD,
4WD;
}
This will group cars by their WheelDrive type.
@MapKeyTemporalThe @MapKeyTemporal will use a Date/Calendar field for grouping, like createdOn.
@Entity
public class Owner {
@Id
private long id;
@OneToMany(mappedBy="owner")
@MapKeyTemporal(TemporalType.TIMESTAMP)
private Map<Date, Car> carMap;
}
@Entity
public class Car {
@Id
private long id;
@ManyToOne
private Owner owner;
@Temporal(TemporalType.TIMESTAMP)
@Column(name="created_on")
private Calendar createdOn;
}
@MapKeyJoinColumnThe @MapKeyJoinColumn requires a third entity, like Manufacturer so that you have an association from Owner to Car and car has also an association to a Manufacturer, so that you can group all Owner's Cars by Manufacturer:
@Entity
public class Owner {
@Id
private long id;
@OneToMany(mappedBy="owner")
@MapKeyJoinColumn(name="manufacturer_id")
private Map<Manufacturer, Car> carMap;
}
@Entity
public class Car {
@Id
private long id;
@ManyToOne
private Owner owner;
@ManyToOne
@JoinColumn(name = "manufacturer_id")
private Manufacturer manufacturer;
}
@Entity
public class Manufacturer {
@Id
private long id;
private String name;
}
Here's a working example of using @MapKey with @OneToMany with a composite @IdClass. It's obviously not the only way to accomplish the objective here, but I felt this was the most maintainable.
@Entity
@Table(name = "template_categories")
@IdClass(TemplateCategoryId.class)
public class TemplateCategory implements Serializable {
private static final long serialVersionUID = 1L;
@Id
long orgId;
@Id
long templateId;
@OneToMany(targetEntity = TemplateEntry.class)
@JoinColumns( {
@JoinColumn(name = "orgId", referencedColumnName = "orgId"),
@JoinColumn(name = "templateId", referencedColumnName = "templateId")
}
)
@MapKey(name="key")
private Map<String, TemplateEntry> keyMap;
source code: https://github.com/in-the-keyhole/jpa-entity-map-examples/blob/master/src/main/java/com/example/demo/mapkey/entity/TemplateCategory.java