Спящий режим / постоянство без @Id - PullRequest
31 голосов
/ 29 мая 2009

У меня есть представление базы данных, которое дает набор результатов, который не имеет истинного первичного ключа. Я хочу использовать Hibernate / Persistence для сопоставления этого набора результатов с объектами Java. Конечно, из-за отсутствия PK я не могу украсить любое поле с помощью @Id.

При развертывании Hibernate жалуется на отсутствие @Id. Как я могу обойти это?

Ответы [ 8 ]

26 голосов
/ 29 мая 2009

Если есть комбинация столбцов, которая делает строку уникальной, смоделируйте класс первичного ключа вокруг комбинации столбцов. Если нет, то вам в основном не повезло - но вам следует пересмотреть дизайн представления, так как это, вероятно, не имеет смысла.

Есть несколько разных подходов:

@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

6 голосов
/ 29 мая 2009

Для каждой сущности вы должны указать хотя бы одно из следующего:

  • один @ Id
  • несколько @Id и @IdClass (для составного первичного ключа)
  • @ EmbeddedId

так, может быть, вы можете создать составной первичный ключ, содержащий несколько полей?

4 голосов
/ 18 мая 2017

Вместо поиска обходных путей в Hibernate может быть проще добавить фиктивный идентификатор в представление базы данных. Давайте предположим, что у нас есть представление 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 ():

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

Теперь мы можем использовать row_id как @Id в JPA / Hibernate / Spring Data:

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

}
1 голос
/ 28 сентября 2012

Вот пример, который имеет 2 клавиши в качестве ключей «Id»: https://gist.github.com/3796379

0 голосов
/ 26 февраля 2019

вы можете просто использовать @EmbeddedId следующим образом:

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

public void setId(Id id) {
    this.id = id;
}
0 голосов
/ 26 февраля 2019

Изменить ваш выбор, используемый для создания представления:

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

и отображение «ID» в качестве первичного ключа.

0 голосов
/ 07 апреля 2016

Хотя это не совсем то, что вы просите, вот небольшой прием, которым я пользуюсь. Пусть запрос выберет «rownum» и определите «rownum» в качестве столбца идентификатора в модели. Это эффективно сделает каждый ряд уникальным для Hibernate.

0 голосов
/ 29 мая 2009

Вы можете проверить, существует ли логический идентификатор и предоставить соответствующую информацию для сопоставления. Hibernate не будет проверять базу данных на наличие определенного первичного ключа.

...