不带@Id的Hibernate/persistence

w1jd8yoj  于 2023-10-23  发布在  其他
关注(0)|答案(9)|浏览(122)

我有一个数据库视图,它产生的结果集没有真正的主键。我想使用Hibernate/Persistence将这个结果集Map到Java对象上。当然,因为没有PK,我不能用@Id装饰任何字段。
在部署时,Hibernate会抱怨缺少@Id。我该如何解决这个问题?

pqwbnv8z

pqwbnv8z1#

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

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

详情如下:https://docs.jboss.org/ejb3/app-server/HibernateAnnotations/reference/en/html_single/index.html#d0e1517
这里有一个帖子描述了一个类似的问题:http://www.theserverside.com/discussions/thread.tss?thread_id=22638

iezvtpos

iezvtpos2#

与其在Hibernate中寻找解决方法,不如在数据库视图中添加dummy id。让我们假设我们有一个PostgreSQL视图,它有两个列,没有一个是唯一的(没有主键,因为PostgreSQL不允许对视图进行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.

}
bjg7j2ky

bjg7j2ky3#

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

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

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

y0u0uwnf

y0u0uwnf4#

下面是一个有两个键作为“Id”键的例子:https://gist.github.com/3796379

vmpqdwk3

vmpqdwk35#

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

rryofs0p

rryofs0p6#

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

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

并将“ID”Map为主键。

mnowg1ta

mnowg1ta7#

你可以使用@EmbeddedId,如下所示:

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

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

xwbd5t1u8#

根据Hibernate用户指南,建议使用pk,因此即使您正在使用数据库端不包含pk的现有项目,您也可以将pk列添加到相关的数据库表并将其与Java实体Map。
Hibernate的建议是这样的:
我们建议您在持久化类上声明一致命名的标识符属性,并使用 Package 器(即非原始)类型(例如长或短)。
关于pk和Hibernate机制的更多细节,请访问这里

ymdaylpp

ymdaylpp9#

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

相关问题