36

我有一个数据库视图,它产生一个没有真正主键的结果集。我想使用 Hibernate/Persistence 将此结果集映射到 Java 对象。当然,因为没有PK,所以不能用@Id.

部署时,Hibernate 抱怨缺少@Id. 我该如何解决这个问题?

4

9 回答 9

28

如果存在使行唯一的列组合,请围绕列组合建模主键类。如果没有,那么您基本上就不走运了——但是您应该重新检查视图的设计,因为它可能没有意义。

有几种不同的方法:

@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 ://docs.jboss.org/ejb3/app-server/HibernateAnnotations/reference/en/html_single/index.html#d0e1517

这是描述类似问题的帖子:http ://www.theserverside.com/discussions/thread.tss?thread_id=22638

于 2009-05-29T13:04:50.283 回答
7

对于每个实体,您必须至少指定以下一项:

  • 一个@Id
  • 多个@Id 和一个@IdClass(用于复合主键)
  • @EmbeddedId

所以也许你可以创建一个复合主键,包含多个字段?

于 2009-05-29T13:03:30.583 回答
6

与其在 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.

}
于 2017-05-18T14:13:34.260 回答
1

这是一个有 2 个键作为“Id”键的示例:https ://gist.github.com/3796379

于 2012-09-27T20:46:34.620 回答
0

您可以检查是否有逻辑明智的 id 并相应地提供映射信息。Hibernate 不会检查数据库是否存在已定义的主键。

于 2009-05-29T13:01:26.843 回答
0

修改用于创建视图的选择:

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

并将“ID”映射为主键。

于 2019-02-26T14:57:50.977 回答
0

您可以按如下方式使用@EmbeddedId:

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

public void setId(Id id) {
    this.id = id;
}
于 2019-02-26T19:02:19.307 回答
0

根据 Hibernate 用户指南,建议使用 pk,因此即使您正在使用数据库端不包含 pk 的现有项目,您也可以将 pk 列添加到相关的数据库表中并与 Java 映射实体。

休眠建议是这样的:

我们建议您在持久类上声明一致命名的标识符属性,并使用包装器(即非原始)类型(例如 Long 或 Integer)。

有关 pk 和 Hibernate 机制的更多详细信息,请访问此处

于 2020-02-11T09:08:01.033 回答
-1

虽然不完全符合您的要求,但这是我使用的一个小技巧。让查询选择“rownum”并将“rownum”定义为模型中的 ID 列。这将有效地使每一行对 Hibernate 都是唯一的。

于 2016-04-06T22:39:26.093 回答