没有@Id的休眠/持久化

时间:2009-05-29 12:54:06

标签: java hibernate primary-key hibernate-annotations

我有一个数据库视图,它产生的结果集没有真正的主键。我想使用Hibernate / Persistence将此结果集映射到Java对象。当然,因为没有PK,我无法用@Id装饰任何字段。

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

9 个答案:

答案 0 :(得分:26)

如果列的组合使行唯一,则在列组合周围建模主键类。如果没有,你基本上没有运气 - 但你应该重新审视视图的设计,因为它可能没有意义。

有几种不同的方法:

@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

答案 1 :(得分:6)

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

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

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

答案 2 :(得分:4)

不是在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.

}

答案 3 :(得分:1)

以下示例包含2个键作为“Id”键:https://gist.github.com/3796379

答案 4 :(得分:0)

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

答案 5 :(得分:0)

修改用于创建视图的选择内容

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

并映射“ ID”作为主键。

答案 6 :(得分:0)

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

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

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

答案 7 :(得分:0)

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

休眠建议如下:

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

有关pk和休眠机制的更多详细信息,请访问here

答案 8 :(得分:-1)

虽然不完全是你所要求的,但这是我使用的一个小技巧。让查询选择" rownum"并定义" rownum"作为模型中的ID列。这将有效地使每一行都是Hibernate独有的。