JPA和Hibernate中@MapKey、@MapKeyColumn和@MapKeyJoinColumn的区别

Posted

技术标签:

【中文标题】JPA和Hibernate中@MapKey、@MapKeyColumn和@MapKeyJoinColumn的区别【英文标题】:Difference between @MapKey, @MapKeyColumn and @MapKeyJoinColumn in JPA and Hibernate 【发布时间】:2014-10-15 21:10:54 【问题描述】:

根据Hibernate documentation,如果我们想使用 Map 作为实体之间的关联,可以使用多个注释。医生说:

或者,映射键被映射到一个或多个专用列。 为了自定义映射使用以下之一 注释:

@MapKeyColumn 如果映射键是基本类型。如果您不指定 列名,属性名后跟下划线 通过 KEY 使用(例如 orders_KEY)。 @MapKeyEnumerated / @MapKeyTemporal 如果映射键类型分别是枚举或日期。 @MapKeyJoinColumn/@MapKeyJoinColumns 如果映射键类型是另一个 实体。 @AttributeOverride/@AttributeOverrides 当映射键是 可嵌入对象。使用钥匙。作为可嵌入对象的前缀 属性名称。也可以使用@MapKeyClass 来定义类型 如果您不使用泛型,则为关键。

通过一些示例,我可以理解@MapKey 仅用于将键映射到目标实体的属性,并且该键仅用于获取记录。 @MapKeyColumn 用于将键映射到目标实体的属性,该键用于保存和获取记录。请告诉我这是否正确?

当我需要使用@MapKeyJoinColumn/@MapKeyJoinColumns & @MapKeyEnumerated / @MapKeyTemporal 时请告诉我

谢谢!

【问题讨论】:

【参考方案1】:

这是一个将@MapKey 与@OneToMany 与复合@IdClass 一起使用的工作示例。这显然不是实现这里目标的唯一方法,但我觉得这是最可维护的。

@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;

源代码: https://github.com/in-the-keyhole/jpa-entity-map-examples/blob/master/src/main/java/com/example/demo/mapkey/entity/TemplateCategory.java

【讨论】:

【参考方案2】:

当您使用Map 时,您始终需要关联至少两个实体。假设我们有一个与Car 实体相关的Owner 实体(CarOwner 有一个FK)。

所以,Owner 将有一个 MapCar(s)

Map<X, Car>

@MapKey

@MapKey 将为您提供Car's 属性,用于将Car 分组到其Owner。例如,如果我们在Car 中有一个vin(车辆识别号)属性,我们可以将其用作carMap 键:

@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

@MapKeyEnumerated 将使用来自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;             

这将按照车轮驱动类型对汽车进行分组。

@MapKeyTemporal

@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

@MapKeyJoinColumn 需要第三个实体,例如 Manufacturer,以便您拥有从 OwnerCar 的关联,并且 car 还具有与 Manufacturer 的关联,这样您就可以对所有 @987654358 进行分组@CarsManufacturer:

@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;

【讨论】:

嗨,弗拉德,如果可能的话,请您看看我的另一篇帖子 - ***.com/questions/25664452/… 非常感谢您的支持。 今晚我去看看 我也有类似的问题。出于某种原因,@MapKey 没有给我预期的结果。你也可以看看这个:***.com/questions/31235462/… 吗? ^^ @VladMihalcea 目前我正在从hibernate 3.3.2 迁移到hibernate 4.3.11。如何迁移@MapKey导致MapKey无法解析为hiberante4中的类型 我在度假。我回来看看。

以上是关于JPA和Hibernate中@MapKey、@MapKeyColumn和@MapKeyJoinColumn的区别的主要内容,如果未能解决你的问题,请参考以下文章

JPASpringData JPA Hibernate和Mybatis 的区别和联系

spring data jpa原生查询中基于地图索引的查询

hibernate中JTA、JPA和Plain JDBC的区别

jpa是啥,和hibernate类似?

如何在 JPA 和 Hibernate 中返回所有值

如何使用 JPA 和 Hibernate 在 UTC 时区中存储日期/时间和时间戳