web-dev-qa-db-fra.com

Entité JPA sans identifiant

J'ai une base de données avec la structure suivante:

CREATE TABLE entity (
    id SERIAL,
    name VARCHAR(255),
    PRIMARY KEY (id)
);

CREATE TABLE entity_property (
    entity_id SERIAL,
    name VARCHAR(255),
    value TEXT
);

Lorsque j'essaie de créer une classe EntityProperty

@Entity
@Table(name="entity_property")
public class EntityProperty {

    private String name;
    private String value;

    @Column(name="name")
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    @Column(name="value", nullable=true, length=255)
    public String getValue() {
        return value;
    }
    public void setValue(String value) {
        this.value = value;
    }
}

J'obtiens l'exception suivante:

org.hibernate.AnnotationException: No identifier specified for entity: package.EntityProperty

Je sais que les entités JPA doivent avoir une clé primaire mais je ne peux pas modifier le schéma de la base de données pour des raisons indépendantes de ma volonté. Est-il possible de créer des entités JPA (Hibernate) qui fonctionneront avec un schéma de base de données comme celui-ci?

45
mikhail

Je suppose que votre entity_property possède une clé composite (entity_id, name)entity_id est une clé étrangère pour entity. Si oui, vous pouvez le mapper comme suit:

@Embeddable
public class EntityPropertyPK {
    @Column(name = "name")
    private String name;

    @ManyToOne
    @JoinColumn(name = "entity_id")
    private Entity entity;

    ...
}

@Entity 
@Table(name="entity_property") 
public class EntityProperty { 
    @EmbeddedId
    private EntityPropertyPK id;

    @Column(name = "value")
    private String value; 

    ...
}
42
axtavt

Je sais que les entités JPA doivent avoir une clé primaire mais je ne peux pas changer la structure de la base de données pour des raisons indépendantes de ma volonté.

Plus précisément, une entité JPA doit avoir un Id défini. Mais un JPA Id ne doit pas nécessairement être mappé sur la clé primaire de la table (et JPA peut en quelque sorte traiter une table sans clé primaire ni contrainte unique).

Est-il possible de créer des entités JPA (Hibernate) qui fonctionneront avec une structure de base de données comme celle-ci?

Si vous avez une colonne ou un ensemble de colonnes dans le tableau qui crée une valeur unique, vous pouvez utiliser cet ensemble unique de colonnes comme Id dans JPA.

Si votre table ne contient aucune colonne unique, vous pouvez utiliser toutes les colonnes comme Id.

Et si votre table a un identifiant mais pas votre entité, faites-en un Embeddable.

26
Pascal Thivent

Voir le livre Java Persistence : Identity and Sequencing

La partie pertinente pour votre question est la Pas de section Clé primaire :

Parfois, votre objet ou votre table n'a pas de clé primaire. La meilleure solution dans ce cas est normalement d'ajouter un identifiant généré à l'objet et à la table. Si vous ne disposez pas de cette option, il existe parfois une colonne ou un ensemble de colonnes dans le tableau qui constituent une valeur unique. Vous pouvez utiliser cet ensemble unique de colonnes comme identifiant dans JPA. Le JPA Id ne doit pas toujours correspondre à la contrainte de clé primaire de la table de base de données, et aucune clé primaire ou contrainte unique n'est requise.

Si votre table n'a vraiment aucune colonne unique, utilisez toutes les colonnes comme identifiant. Généralement, lorsque cela se produit, les données sont en lecture seule, donc même si le tableau autorise les lignes en double avec les mêmes valeurs, les objets seront de toute façon les mêmes, donc peu importe que JPA pense qu'ils sont le même objet. Le problème avec l'autorisation des mises à jour et des suppressions est qu'il n'y a aucun moyen d'identifier de manière unique la ligne de l'objet, donc toutes les lignes correspondantes seront mises à jour ou supprimées.

Si votre objet n'a pas d'identifiant, mais que sa table en a, c'est bien. Faites de l'objet un objet Embeddable, les objets intégrables n'ont pas d'identifiant. Vous aurez besoin d'un Entity qui contient ce Embeddable pour persister et l'interroger.

20
Gilberto

Je suppose que vous pouvez utiliser @CollectionOfElements (pour l'hibernation/jpa 1)/ @ElementCollection (jpa 2) pour mapper une collection de "propriétés d'entité" à un List dans entity.

Vous pouvez créer le type EntityProperty et l'annoter avec @Embeddable

3
Bozho

S'il existe un mappage un à un entre entité et property_property, vous pouvez utiliser entity_id comme identifiant.

1
Qwerky