Difference between @MapKey, @MapKeyColumn and @MapKeyJoinColumn in JPA and Hibernate
As per Hibernate documentation, there are multiple annotations available if we want to use Map as an association between our entities. The doc says:
Alternatively the map key is mapped to a dedicated column or columns. In order to customize the mapping use one of the following annotations:
@MapKeyColumn if the map key is a basic type. If you don't specify the column name, the name of the property followed by underscore followed by KEY is used (for example orders_KEY). @MapKeyEnumerated / @MapKeyTemporal if the map key type is respectively an enum or a Date. @MapKeyJoinColumn/@MapKeyJoinColumns if the map key type is another entity. @AttributeOverride/@AttributeOverrides when the map key is a embeddable object. Use key. as a prefix for your embeddable object property names. You can also use @MapKeyClass to define the type of the key if you don't use generics.
By doing some examples I am able to understand that @MapKey is just used to map the key to a property of target entity and this key is used only for fetching records. @MapKeyColumn is used to map the key to a property of target entity and this key is used to save as well as fetching records. Please let me know if this is correct?
Also please let me know when I need to use @MapKeyJoinColumn/@MapKeyJoinColumns & @MapKeyEnumerated / @MapKeyTemporal
Thanks!
Solution 1:
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>
@MapKey
The @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;
}
@MapKeyEnumerated
The @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.
@MapKeyTemporal
The @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;
}
@MapKeyJoinColumn
The @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;
}