JPA 和 Hibernate 中的@MapKey、@MapKeyColumn和@MapKeyJoinColumn之间的差异

2022-09-01 11:38:34

根据Hibernate文档,如果我们想使用Map作为实体之间的关联,则有多个注释可用。文档说:

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

@MapKeyColumn映射键是否为基本类型。如果未指定列名,则使用属性名称后跟下划线和 KEY(例如orders_KEY)。@MapKeyEnumerated/@MapKeyTemporal映射键类型是否分别是枚举或日期。@MapKeyJoinColumn/@MapKeyJoinColumns映射键类型是否为其他实体。@AttributeOverride/@AttributeOverrides映射键是可嵌入对象时。使用密钥。作为可嵌入对象属性名称的前缀。如果不使用泛型,还可以使用 @MapKeyClass来定义密钥的类型。

通过做一些例子,我能够理解@MapKey只是用来将键映射到目标实体的属性,而这个键只用于获取记录。@MapKeyColumn用于将键映射到目标实体的属性,此键用于保存和获取记录。请让我知道这是正确的?

另外,请让我知道我何时需要使用@MapKeyJoinColumn / @MapKeyJoinColumns和@MapKeyEnumerated / @MapKeyTemporal

谢谢!


答案 1

使用 时,始终需要至少关联两个实体。假设我们有一个与该实体相关的实体( 具有 FK 到 )。MapOwnerCarCarOwner

所以,将有一个:OwnerMapCar(s)

Map<X, Car>

@MapKey

将为您提供用于将 a 分组到其 .例如,如果我们在 中有一个(车辆识别号)属性,我们可以将其用作键:@MapKeyCar'sCarOwnervinCarcarMap

@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

将使用 来自 的枚举,例如:@MapKeyEnumeratedCarWheelDrive

@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

将使用 / 字段进行分组,如 .@MapKeyTemporalDateCalendarcreatedOn

@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

需要第三个实体,比如说你有一个关联从 to 和 car 也有一个关联到 a ,这样你就可以按以下方式分组:@MapKeyJoinColumnManufacturerOwnerCarManufacturerOwner'sCarsManufacturer

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

答案 2

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

@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


推荐