Ruhezustand/Persistenz ohne @Id

Lesezeit: 4 Minuten

Ich habe eine Datenbankansicht, die eine Ergebnismenge liefert, die keinen echten Primärschlüssel hat. Ich möchte Hibernate/Persistence verwenden, um diese Ergebnismenge auf Java-Objekte abzubilden. Da es kein PK gibt, kann ich natürlich kein Feld damit dekorieren @Id.

Bei der Bereitstellung beschwert sich Hibernate über das fehlende @Id. Wie kann ich das umgehen?

Wenn eine Spaltenkombination eine Zeile eindeutig macht, modellieren Sie eine Primärschlüsselklasse um die Spaltenkombination herum. Wenn dies nicht der Fall ist, haben Sie im Grunde kein Glück – aber Sie sollten das Design der Ansicht erneut überprüfen, da es wahrscheinlich keinen Sinn ergibt.

Es gibt ein paar verschiedene Ansätze:

@Entity
public class RegionalArticle implements Serializable {

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

@Embeddable
public class RegionalArticlePk implements Serializable { ... }

Oder:

@Entity
public class RegionalArticle implements Serializable {

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

public class RegionalArticlePk implements Serializable { ... }

Die Einzelheiten sind hier: http://docs.jboss.org/ejb3/app-server/HibernateAnnotations/reference/en/html_single/index.html#d0e1517

Hier ist ein Beitrag, der ein ähnliches Problem beschreibt: http://www.theserverside.com/discussions/thread.tss?thread_id=22638

  • Aber was passiert, wenn ein solcher zusammengesetzter Satz von Spalten einen NULL-Wert enthält, ich keinen PK habe, aber etwas wie UNIQUE Constraint oder Index definiert habe, wie geht Hibernate damit um? Klingt wie ein Paradox: “@Id” mit Nullable-Werten kann nicht existieren und kann ohne definierte “@Id” nicht gespeichert werden.

    – Osy

    11. August ’18 um 22:28

  • > Ansicht macht keinen Sinn. Ich stimme zu. Projektionen, die von gespeicherten Prozeduren zurückgegeben werden, sind absolut gültige Ansichten, die keine Bezeichner enthalten.

    – Dragas

    2. November ’19 um 21:46

Für jede Entität müssen Sie mindestens eine der folgenden Angaben machen:

  • eins @Ausweis
  • mehrere @Id und eine @IdClass (für einen zusammengesetzten Primärschlüssel)
  • @EmbeddedId

Vielleicht können Sie also einen zusammengesetzten Primärschlüssel erstellen, der mehrere Felder enthält?

Anstatt im Ruhezustand nach Problemumgehungen zu suchen, ist es möglicherweise einfacher, Dummy-IDs in Ihrer Datenbankansicht hinzuzufügen. Nehmen wir an, wir haben eine PostgreSQL-Ansicht mit zwei Spalten und keine davon ist eindeutig (und es gibt keinen Primärschlüssel, da Postgres keine PK- oder andere Einschränkungen für Ansichten zulässt) ex.

| employee_id | project_name |
|:------------|:-------------|
| 1           | Stack01      |
| 1           | Jira01       |
| 1           | Github01     |
| 2           | Stack01      |
| 2           | Jira01       |
| 3           | Jira01       |
------------------------------

Welches wird durch die folgende Abfrage dargestellt:

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

Wir können eine Dummy-ID mit row_number() hinzufügen:

SELECT row_number() OVER (ORDER BY subquery.employee_id) AS row_id

wie in diesem Beispiel:

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;

Und die Tabelle sieht so aus:

| row_id      | employee_id | project_name |
|:------------|:------------|:-------------|
| 1           | 1           | Stack01      |
| 2           | 1           | Jira01       |
| 3           | 1           | Github01     |
| 4           | 2           | Stack01      |
| 5           | 2           | Jira01       |
| 6           | 3           | Jira01       |
-------------------------------------------

Jetzt können wir row_id als @Id in JPA/Hibernate/Spring Data verwenden:

@Id
@Column(name = "row_id")
private Integer id;

Wie im Beispiel:

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

}

  • Es ist schwer zu sehen, dass dies ein Klarheitsgewinn gegenüber der obigen eingebetteten ID ist, es sei denn, Sie benötigen tatsächlich eine eindeutige ID. Gibt es auch Leistungsüberlegungen?

    – Michael Häfele

    3. November ’17 um 19:42

  • beachten Sie, dass rownum und row number() over spielen sehr schlecht mit Cache (gleiche Abfrage, unterschiedliche Parameter und dann haben unterschiedliche Ergebnisse die gleiche ID…)

    – p3consulting

    18. Mai ’18 um 11:54

  • In MySQL-Versionen unter 8.0 ist keine Rownum-Funktion verfügbar. Aber es ist möglich, den folgenden Ansatz zu verwenden [stackoverflow.com/questions/1895110/row-number-in-mysql/… as an alternative. Just in case anybody is looking for alternative.

    – Eugene Maysyuk

    Jan 29 ’21 at 15:14


Here is an example that has 2 keys as “Id” keys: https://gist.github.com/3796379

You could check if there is logic wise an id and provide mapping information accordingly. Hibernate will not check the database for existence of a defined primary key.

RuhezustandPersistenz ohne @Id
Peter S.

Modify your select used for view creation:

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

and map “ID” as primary key.

RuhezustandPersistenz ohne @Id
Victoria Serkov

you could just use @EmbeddedId as follows:

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

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

.

214600cookie-checkRuhezustand/Persistenz ohne @Id

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy