Вопрос

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

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

Это было полезно?

Решение

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

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

@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

Другие советы

Для каждой сущности вы должны указать по крайней мере одно из следующих значений:

  • один @Идентификатор
  • множественный @Id и @IdClass (для составного первичного ключа)
  • @Встроенный идентификатор

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

Вместо поиска обходных путей в 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:

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

}

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

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

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

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

и сопоставьте "ID" с первичным ключом.

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top