Разница между @MapKey, @MapKeyColumn и @MapKeyJoinColumn в JPA и Hibernate

В соответствии с документацией Hibernate имеется несколько аннотаций, если мы хотим использовать карту как ассоциацию между нашими объектами. Док говорит:

В качестве альтернативы ключ карты отображается в выделенный столбец или столбцы. Чтобы настроить отображение, используйте один из следующих Аннотации:

@MapKeyColumn, если ключ карты является основным типом. Если вы не указали имя столбца, имя свойства, за которым следует знак подчеркивания используется KEY (например, orders_KEY). @MapKeyEnumerated/ @MapKeyTemporal, если тип ключа карты является соответственно перечислением или датой. @MapKeyJoinColumn/@MapKeyJoinColumns, если тип ключа карты - другой организация. @AttributeOverride/@AttributeOverrides, когда ключ карты является встраиваемый объект. Используйте ключ. как префикс для вашего встраиваемого объекта имена свойств. Вы также можете использовать @MapKeyClass для определения типа ключ, если вы не используете дженерики.

Сделав несколько примеров, я могу понять, что @MapKey просто используется для сопоставления ключа с объектом целевого объекта, и этот ключ используется только для получения записей. @MapKeyColumn используется для сопоставления ключа с объектом целевого объекта, и этот ключ используется для сохранения, а также для извлечения записей. Пожалуйста, дайте мне знать, если это правильно.

Также, пожалуйста, дайте мне знать, когда мне нужно использовать @MapKeyJoinColumn/@MapKeyJoinColumns и @MapKeyEnumerated/@MapKeyTemporal

Спасибо!

Ответ 1

Когда вы используете Map, вам всегда нужно связать не менее двух объектов. Скажем, мы имеем объект Owner, относящийся к объекту Car (Car имеет FK до Owner).

Итак, Owner будет иметь Map of Car(s):

Map<X, Car>
  • @MapKey даст вам поле Car's, используемое для группировки нескольких Car(s) в Owner:

  • @MapKeyEnumerated будет использовать Enum из Car, например 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;             
    }   
    

    Это будет группировать автомобили по типу WheelDrive.

  • @MapKeyTemporal будет использовать поле Date/Calendar для группировки, например 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 требуется третья сущность, например Manufacturer, так что у вас есть связь от Owner до Car, а автомобиль также имеет связь с Manufacturer, так что вы можете группировать все Owner's Cars на 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;
    }