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?
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
Pour chaque entité, vous devez désigner au moins l'un des éléments suivants:
alors peut-être que vous pouvez créer une clé primaire composite, contenant plusieurs champs?
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.
}
Voici un exemple qui a 2 clés comme clés "Id": https://Gist.github.com/3796379
vous pouvez simplement utiliser @EmbeddedId comme suit:
@EmbeddedId
public Id getId() {
return id;
}
public void setId(Id id) {
this.id = id;
}
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.
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.