web-dev-qa-db-fra.com

Mise en veille prolongée / persistance sans @Id

J'ai une vue de base de données qui produit un jeu de résultats qui n'a pas de véritable clé primaire. Je veux utiliser Hibernate/Persistence pour mapper cet ensemble de résultats sur des objets Java. Bien sûr, comme il n'y a pas de PK, je ne peux décorer aucun champ avec @Id.

Lors du déploiement, Hibernate se plaint de l'absence de @Id. Comment contourner cela?

31
Miguel

S'il existe une combinaison de colonnes qui rend une ligne unique, modélisez une classe de clé primaire autour de la combinaison de colonnes. Si ce n'est pas le cas, vous n'avez pas de chance, mais vous devriez réexaminer la conception de la vue car cela n'a probablement aucun sens.

Il existe plusieurs approches différentes:

@Entity
public class RegionalArticle implements Serializable {

    @Id
    public RegionalArticlePk getPk() { ... }
}

@Embeddable
public class RegionalArticlePk implements Serializable { ... }

Ou:

@Entity
public class RegionalArticle implements Serializable {

    @EmbeddedId
    public RegionalArticlePk getPk() { ... }
}

public class RegionalArticlePk implements Serializable { ... }

Les détails sont ici: http://docs.jboss.org/ejb3/app-server/HibernateAnnotations/reference/en/html_single/index.html#d0e1517

Voici une publication qui décrit un problème similaire: http://www.theserverside.com/discussions/thread.tss?thread_id=22638

26

Pour chaque entité, vous devez désigner au moins l'un des éléments suivants:

  • un @ Id
  • plusieurs @Id et une @IdClass (pour une clé primaire composite)
  • @EmbeddedId

alors peut-être que vous pouvez créer une clé primaire composite, contenant plusieurs champs?

6
Fortega

Au lieu de rechercher des solutions de contournement dans Hibernate, il pourrait être plus facile d'ajouter un identifiant factice dans la vue de votre base de données. Supposons que nous avons une vue PostgreSQL avec deux colonnes et aucune d'entre elles n'est unique (et il n'y a pas de clé primaire car Postgres ne permet pas de créer PK ou toute autre contrainte sur les vues) ex.

| employee_id | project_name |
|:------------|:-------------|
| 1           | Stack01      |
| 1           | Jira01       |
| 1           | Github01     |
| 2           | Stack01      |
| 2           | Jira01       |
| 3           | Jira01       |
------------------------------

Qui est représenté par la requête suivante:

CREATE OR REPLACE VIEW someschema.vw_emp_proj_his AS
    SELECT DISTINCT e.employee_id,
                    pinf.project_name
    FROM someschema.project_info pinf
    JOIN someschema.project_employee pe ON pe.proj_id = pinf.proj_id
    JOIN someschema.employees e ON e.employee_id = pe.emloyee_id

Nous pouvons ajouter un identifiant factice en utilisant row_number ():

SELECT row_number() OVER (ORDER BY subquery.employee_id) AS row_id

comme dans cet exemple:

CREATE OR REPLACE VIEW someschema.vw_emp_proj_his AS
SELECT row_number() OVER (ORDER BY subquery.employee_id) AS row_id,
       subquery.employee_id,
       subquery.project_name
FROM
  (SELECT DISTINCT e.employee_id,
                   pinf.project_name
   FROM someschema.project_info pinf
   JOIN someschema.project_employee pe ON pe.proj_id = pinf.proj_id
   JOIN someschema.employees e ON e.employee_id = pe.emloyee_id ) subquery;

Et le tableau ressemblera à ceci:

| row_id      | employee_id | project_name |
|:------------|:------------|:-------------|
| 1           | 1           | Stack01      |
| 2           | 1           | Jira01       |
| 3           | 1           | Github01     |
| 4           | 2           | Stack01      |
| 5           | 2           | Jira01       |
| 6           | 3           | Jira01       |
-------------------------------------------

Maintenant, nous pouvons utiliser row_id comme @Id dans JPA/Hibernate/Spring Data:

@Id
@Column(name = "row_id")
private Integer id;

Comme dans l'exemple:

@Entity
@Table(schema = "someschema", name = "vw_emp_proj_his")
public class EmployeeProjectHistory {

    @Id
    @Column(name = "row_id")
    private Integer id;

    @Column(name = "employee_id")
    private Integer employeeId;

    @Column(name = "project_name")
    private String projectName;

//Getters, setters etc.

}
4
luke

Voici un exemple qui a 2 clés comme clés "Id": https://Gist.github.com/3796379

1
rogerdpack

vous pouvez simplement utiliser @EmbeddedId comme suit:

@EmbeddedId
public Id getId() {
    return id;
}

public void setId(Id id) {
    this.id = id;
}
0
Victoria Serkov

Modifiez votre sélection utilisée pour la création de la vue:

SELECT
   ROWNUM ID, -- or use nextval of some sequence
   -- other columns
FROM
  TABLE

et mappez "ID" comme clé primaire.

0
Peter S.

Vous pouvez vérifier s'il existe un identifiant logique et fournir des informations de mappage en conséquence. Hibernate ne vérifie pas l'existence d'une clé primaire définie dans la base de données.

0
rudolfson