没有@Id的休眠/持久化

31 java hibernate primary-key hibernate-annotations

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

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

Edw*_*ges 26

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

有几种不同的方法:

@Entity
public class RegionalArticle implements Serializable {

    @Id
    public RegionalArticlePk getPk() { ... }
}

@Embeddable
public class RegionalArticlePk implements Serializable { ... }
Run Code Online (Sandbox Code Playgroud)

要么:

@Entity
public class RegionalArticle implements Serializable {

    @EmbeddedId
    public RegionalArticlePk getPk() { ... }
}

public class RegionalArticlePk implements Serializable { ... }
Run Code Online (Sandbox Code Playgroud)

详细信息如下: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

  • 但是,如果这样的复合列集包含一个可为空的列,会发生什么,我没有 PK,但我定义了诸如 UNIQUE 约束或索引之类的东西,Hibernate 如何处理它?听起来像是一个悖论:具有可为空值的“@Id”不能存在,并且如果没有定义“@Id”则无法保存。 (2认同)

For*_*ega 6

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

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

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


luk*_*uke 6

与在 Hibernate 中搜索解决方法不同,在数据库视图中添加虚拟 ID 可能更容易。假设我们有包含两列的 PostgreSQL 视图,并且它们都不是唯一的(并且没有主键,因为 Postgres 不允许对视图进行 PK 或任何其他约束)例如。

| employee_id | project_name |
|:------------|:-------------|
| 1           | Stack01      |
| 1           | Jira01       |
| 1           | Github01     |
| 2           | Stack01      |
| 2           | Jira01       |
| 3           | Jira01       |
------------------------------
Run Code Online (Sandbox Code Playgroud)

由以下查询表示:

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
Run Code Online (Sandbox Code Playgroud)

我们可以使用 row_number() 添加虚拟 ID:

SELECT row_number() OVER (ORDER BY subquery.employee_id) AS row_id
Run Code Online (Sandbox Code Playgroud)

就像在这个例子中:

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;
Run Code Online (Sandbox Code Playgroud)

该表将如下所示:

| row_id      | employee_id | project_name |
|:------------|:------------|:-------------|
| 1           | 1           | Stack01      |
| 2           | 1           | Jira01       |
| 3           | 1           | Github01     |
| 4           | 2           | Stack01      |
| 5           | 2           | Jira01       |
| 6           | 3           | Jira01       |
-------------------------------------------
Run Code Online (Sandbox Code Playgroud)

现在我们可以在 JPA/Hibernate/Spring Data 中使用 row_id 作为 @Id:

@Id
@Column(name = "row_id")
private Integer id;
Run Code Online (Sandbox Code Playgroud)

就像在这个例子中:

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

}
Run Code Online (Sandbox Code Playgroud)