web-dev-qa-db-fra.com

Différence entre @MapKey, @MapKeyColumn et @MapKeyJoinColumn dans JPA et Hibernate

Selon documentation Hibernate , plusieurs annotations sont disponibles si nous voulons utiliser Map comme association entre nos entités. Le doc dit:

Alternativement, la clé de mappage est mappée sur une ou plusieurs colonnes dédiées. Afin de personnaliser le mappage, utilisez l'une des annotations suivantes:

@MapKeyColumn si la clé de carte est un type de base. Si vous ne spécifiez pas le nom de la colonne, le nom de la propriété suivi du trait de soulignement suivi de KEY est utilisé (par exemple Orders_KEY). @MapKeyEnumerated/@MapKeyTemporal si le type de clé de carte est respectivement une énumération ou une date. @ MapKeyJoinColumn/@ MapKeyJoinColumns si le type de clé de carte est une autre entité. @ AttributeOverride/@ AttributeOverrides lorsque la clé de carte est un objet intégrable. Utilisez la clé. comme préfixe pour vos noms de propriétés d'objet intégrables. Vous pouvez également utiliser @MapKeyClass pour définir le type de la clé si vous n'utilisez pas de génériques.

En faisant quelques exemples, je peux comprendre que @MapKey est juste utilisé pour mapper la clé à une propriété de l'entité cible et cette clé est utilisée uniquement pour récupérer des enregistrements. @MapKeyColumn est utilisé pour mapper la clé sur une propriété de l'entité cible et cette clé est utilisée pour enregistrer ainsi que pour récupérer des enregistrements. Veuillez me faire savoir si c'est correct?

Veuillez également me faire savoir quand j'ai besoin d'utiliser @ MapKeyJoinColumn/@ MapKeyJoinColumns & @MapKeyEnumerated/@MapKeyTemporal

Merci!

22
Chaitanya

Lorsque vous utilisez un Map, vous devez toujours associer au moins deux entités. Disons que nous avons une entité Owner qui se rapporte à l'entité Car (Car a un FK à Owner).

Ainsi, le Owner aura un Map de Car(s):

Map<X, Car>

@MapKey

Le @MapKey vous donnera le Car's propriété utilisée pour regrouper un Car dans son Owner. Par exemple, si nous avons une propriété vin (numéro d'identification du véhicule) dans Car, nous pourrions l'utiliser comme clé 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

Le @MapKeyEnumerated utilisera un Enum de Car, comme 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;             
}

Cela regroupera les voitures par leur type de WheelDrive.

@MapKeyTemporal

Le @MapKeyTemporal utilisera un champ Date/Calendar pour le regroupement, comme 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

Le @MapKeyJoinColumn nécessite une troisième entité, comme Manufacturer pour que vous ayez une association de Owner à Car et car a également une association à un Manufacturer, donc que vous pouvez regrouper tous Owner'sCars par 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;
}
38
Vlad Mihalcea

Voici un exemple pratique d'utilisation de @MapKey avec @OneToMany avec une @IdClass composite. Ce n'est évidemment pas la seule façon d'atteindre l'objectif ici, mais j'ai senti que c'était la plus maintenable.

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

code source: https://github.com/in-the-keyhole/jpa-entity-map-examples/blob/master/src/main/Java/com/example/demo/mapkey/entity/TemplateCategory .Java

0
Ryan