我有一个数据库视图,它产生一个没有真正主键的结果集。我想使用 Hibernate/Persistence 将此结果集映射到 Java 对象。当然,因为没有PK,所以不能用@Id
.
部署时,Hibernate 抱怨缺少@Id
. 我该如何解决这个问题?
我有一个数据库视图,它产生一个没有真正主键的结果集。我想使用 Hibernate/Persistence 将此结果集映射到 Java 对象。当然,因为没有PK,所以不能用@Id
.
部署时,Hibernate 抱怨缺少@Id
. 我该如何解决这个问题?
如果存在使行唯一的列组合,请围绕列组合建模主键类。如果没有,那么您基本上就不走运了——但是您应该重新检查视图的设计,因为它可能没有意义。
有几种不同的方法:
@Entity
public class RegionalArticle implements Serializable {
@Id
public RegionalArticlePk getPk() { ... }
}
@Embeddable
public class RegionalArticlePk implements Serializable { ... }
或者:
@Entity
public class RegionalArticle implements Serializable {
@EmbeddedId
public RegionalArticlePk getPk() { ... }
}
public class RegionalArticlePk implements Serializable { ... }
这是描述类似问题的帖子:http ://www.theserverside.com/discussions/thread.tss?thread_id=22638
与其在 Hibernate 中搜索解决方法,不如在数据库视图中添加虚拟 id 可能更容易。假设我们有两列的 PostgreSQL 视图,并且它们都不是唯一的(并且没有主键,因为 Postgres 不允许对视图进行 PK 或任何其他约束)例如。
| employee_id | project_name |
|:------------|:-------------|
| 1 | Stack01 |
| 1 | Jira01 |
| 1 | Github01 |
| 2 | Stack01 |
| 2 | Jira01 |
| 3 | Jira01 |
------------------------------
由以下查询表示:
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
我们可以使用 row_number() 添加虚拟 id:
SELECT row_number() OVER (ORDER BY subquery.employee_id) AS row_id
就像在这个例子中:
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;
表格将如下所示:
| row_id | employee_id | project_name |
|:------------|:------------|:-------------|
| 1 | 1 | Stack01 |
| 2 | 1 | Jira01 |
| 3 | 1 | Github01 |
| 4 | 2 | Stack01 |
| 5 | 2 | Jira01 |
| 6 | 3 | Jira01 |
-------------------------------------------
现在我们可以在 JPA/Hibernate/Spring Data 中使用 row_id 作为@Id:
@Id
@Column(name = "row_id")
private Integer id;
就像在示例中一样:
@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.
}
这是一个有 2 个键作为“Id”键的示例:https ://gist.github.com/3796379
您可以检查是否有逻辑明智的 id 并相应地提供映射信息。Hibernate 不会检查数据库是否存在已定义的主键。
修改用于创建视图的选择:
SELECT
ROWNUM ID, -- or use nextval of some sequence
-- other columns
FROM
TABLE
并将“ID”映射为主键。
您可以按如下方式使用@EmbeddedId:
@EmbeddedId
public Id getId() {
return id;
}
public void setId(Id id) {
this.id = id;
}
根据 Hibernate 用户指南,建议使用 pk,因此即使您正在使用数据库端不包含 pk 的现有项目,您也可以将 pk 列添加到相关的数据库表中并与 Java 映射实体。
休眠建议是这样的:
我们建议您在持久类上声明一致命名的标识符属性,并使用包装器(即非原始)类型(例如 Long 或 Integer)。
有关 pk 和 Hibernate 机制的更多详细信息,请访问此处
虽然不完全符合您的要求,但这是我使用的一个小技巧。让查询选择“rownum”并将“rownum”定义为模型中的 ID 列。这将有效地使每一行对 Hibernate 都是唯一的。