Hibernar / persistencia sin @Id

Tengo una vista de base de datos que arroja un conjunto de resultados que no tiene una clave primaria verdadera. Quiero usar Hibernate / Persistence para mapear este conjunto de resultados en objetos Java. Por supuesto, como no hay PK, no puedo decorar ningún campo con @Id .

Al implementar, Hibernate se queja sobre el @Id perdido. ¿Cómo puedo solucionar esto?

Si hay una combinación de columnas que hace que una fila sea única, modele una clase de clave principal alrededor de la combinación de columnas. Si no es así, básicamente no tienes suerte, pero deberías volver a examinar el diseño de la vista, ya que probablemente no tenga sentido.

Hay un par de enfoques diferentes:

 @Entity public class RegionalArticle implements Serializable { @Id public RegionalArticlePk getPk() { ... } } @Embeddable public class RegionalArticlePk implements Serializable { ... } 

O:

 @Entity public class RegionalArticle implements Serializable { @EmbeddedId public RegionalArticlePk getPk() { ... } } public class RegionalArticlePk implements Serializable { ... } 

Los detalles están aquí: http://docs.jboss.org/ejb3/app-server/HibernateAnnotations/reference/en/html_single/index.html#d0e1517

Aquí hay una publicación que describe un problema similar: http://www.theserverside.com/discussions/thread.tss?thread_id=22638

Para cada entidad, debe designar al menos uno de los siguientes:

  • un @Id
  • multiple @Id y @IdClass (para una clave primaria compuesta)
  • @EmbeddedId

entonces tal vez puedas crear una clave primaria compuesta, que contenga múltiples campos?

En lugar de buscar soluciones en Hibernate, podría ser más fácil agregar una identificación ficticia en la vista de la base de datos. Supongamos que tenemos vista de PostgreSQL con dos columnas y ninguna de ellas es única (y no hay clave primaria ya que Postgres no permite hacer PK u otras restricciones en las vistas) ej.

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

Que se representa mediante la siguiente consulta:

 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 

Podemos agregar una identificación ficticia usando row_number ():

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

como en este ejemplo:

 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; 

Y la mesa se verá así:

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

Ahora podemos usar row_id como @Id en JPA / Hibernate / Spring Data:

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

Como en el ejemplo:

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

Aquí hay un ejemplo que tiene 2 claves como “Id”: https://gist.github.com/3796379

Podría verificar si existe una idoneidad lógica y proporcionar información de mapeo en consecuencia. Hibernate no verificará la existencia de una clave primaria definida en la base de datos.

Si bien no es exactamente lo que estás pidiendo, aquí hay un pequeño truco que uso. Haga que la consulta seleccione “rownum” y defina “rownum” como su columna de ID en el modelo. Eso hará que cada fila sea única para Hibernate.