# Zusammengesetzte Schlüssel mit Entität



## mwr (24. Nov 2010)

Hallo,

ich bin relativ neu bei Hibernate und versuche gerade unsere Datenbank per Hibernate mit Annotationen zu mappen.
Dabei habe ich ein grundlegendes Problem, bei dem ich nicht weiter komme.
Viele Entitäten bei uns haben im Schlüssel eine Firma enthalten, die wiederum selbst ein Entität ist.

Beispieltabelle Firma:
int firma_id
varchar bezeichnung

Beispieltabelle Kostenstelle:
int ko_firma_id
int kostenstellen_id
varchar bezeichnung

Die Klasse der Kostenstelle müsste nun (stark vereinfacht) so aussehen:



```
public class Kostenstelle {

  private Firma firma;
  private int id;
  private String bezeichnung;


  // getter und setter

}
```

Somit muss ich bei der Kostenstelle mit einem zusammengesetzten Schlüssel arbeiten.
Ich habe schon einiges probiert mit EmbeddedId und MapsId bekomme es aber nicht richtig hin, so das die Id der Firma auf das Feld ko_firma_id gemappt wird.

Wie macht man es richtig, so das man mit dem Objekt Firma und einem Integerwert die Kostenstelle laden kann?

Als zweites stellt sich mir die Frage, wie eine Kostenstelle z.B. in einem Buchungssatz-Objekt angegeben wird mit den beiden Parameter Firma und Kostenstellen-Id.

Vielen Dank für eure Hilfe im voraus!


----------



## tfa (24. Nov 2010)

Ich würde sagen, kostenstelle_id ist der Primärschlüssel und ko_firma_id ein Foreign Key auf Firma.firma_id. Probier es mal mit Mapping, OneToMany oder OneToOne - was auch immer du brauchst.


----------



## mwr (24. Nov 2010)

tfa hat gesagt.:


> Ich würde sagen, kostenstelle_id ist der Primärschlüssel und ko_firma_id ein Foreign Key auf Firma.firma_id. Probier es mal mit Mapping, OneToMany oder OneToOne - was auch immer du brauchst.



Lieder nicht. Der Primärschlüssel setzt sich aus Firma und Kostenstellen-Id zusammen. Eine Kostenstellen_Id 10 kann es mit Firma 1 und mit Firma 2 geben die jeweils eine unterschiedliche Bedeutung haben.


----------



## tfa (24. Nov 2010)

Das heißt, id ist gar kein Kunstschlüssel sondern hat eine Bedeutung? Wie unpraktisch.


----------



## maki (24. Nov 2010)

tfa hat gesagt.:


> Das heißt, id ist gar kein Kunstschlüssel sondern hat eine Bedeutung? Wie unpraktisch.


Hehehe.. klassischer Fehler.

mwr, 

fachliche Schlüssel sind schlecht, gehört zu den Grundlagen für RDBMS.

Ids sollten nur intern verwendet werden und keine fachliche Bedeutung haben, sonst gibt es noch mehr Probleme.


----------



## mwr (24. Nov 2010)

tfa hat gesagt.:


> Das heißt, id ist gar kein Kunstschlüssel sondern hat eine Bedeutung? Wie unpraktisch.



Genau, ID hat eine Bedeutung (Kostenstellennummer). Mit der ID der Kostenstelle habe eigentlich auch kein Problem sondern eher mit der Id der Firma, die auf die ko_firma_id gemappt werden muß. Als zweites stellt sich mir dann die Frage wie dann der Zugriff auf die Kostennstelle in einer anderen Entität angegeben wird die mit Firma und Kostenstellen-Id auf die Kostenstelle zugreift.


----------



## mwr (24. Nov 2010)

maki hat gesagt.:


> Hehehe.. klassischer Fehler.
> 
> mwr,
> 
> ...



Naja, wir arbeiten seit über 20 Jahren mit relationalen Datenbanken und in einer Zeichenorientierten Systemumgebung sind Schlüssel mit "fachlicher Bedeutung" nichts ungewöhnliches.


----------



## maki (24. Nov 2010)

> Naja, wir arbeiten seit über 20 Jahren mit relationalen Datenbanken und in einer Zeichenorientierten Systemumgebung sind Schlüssel mit "fachlicher Bedeutung" nichts ungewöhnliches.


Nix für ungut, aber dann macht ihr seit 20 Jahren etwas falsch.

Aber dieses Thema ist uralt und wird nicht richtiger wenn man es seit 20 Jahren falsch praktiziert.
Was wäre wenn sich die Kostenstellennummer oder ein anderer Fachlicher Schlüssel ändert?
Mal schnell alle Datenssätze neu erzeugen, inkl. die der Mappingtabellen? 

Ich kenne das aus alten, nicht relationalen DBs wie zB. ADABAS C, aber selbst hat man interne IDs.


----------



## tfa (24. Nov 2010)

Solange man nur relational denkt und arbeitet mag das klappen (muss aber auch nicht). Wenn allerdings objektorientierte Programmierung dazu kommt und man wie hier einen OR-Mapper einsetzt, sollte man sich ganz schnell von fachlichen Schlüsseln verabschieden. Das macht nur Probleme.


----------



## mwr (24. Nov 2010)

Bedeutete das, ich kann diese Konstellation mit Hibernate gar nicht abdecken.


----------



## tfa (24. Nov 2010)

Es gibt Composite IDs in Hibernate: Chapter*5.*Basic O/R Mapping
Vielleicht hilft das. (Eine Migration in ein Kunstschlüssel-basiertes Modell ist wahrscheinlich illusorisch).


----------



## André Uhres (24. Nov 2010)

Hallo mwr,

ich arbeite zwar nicht mit Hibernate, aber etwas in dieser Art hab ich schon einmal gemacht. Im Prinzip mache ich die zusammengesetzte Primary Key in eine extra Klasse, die Embeddable ist, etwa so:


```
public class Kostenstelle implements Serializable {

    private static final long serialVersionUID = 1L;
    @EmbeddedId
    protected KostenstellePK key;
    @Column(name = "bezeichnung")
    private String bezeichnung;
```


```
@Embeddable
public class KostenstellePK implements Serializable {

    @Basic(optional = false)
    @Column(name = "firmaID")
    private Integer firmaID;
    @Basic(optional = false)
    @Column(name = "kostenstelleID")
    private Integer kostenstelleID;
```
Gruß,
André


----------



## mwr (24. Nov 2010)

André Uhres hat gesagt.:


> Hallo mwr,
> 
> ich arbeite zwar nicht mit Hibernate, aber etwas in dieser Art hab ich schon einmal gemacht. Im Prinzip mache ich die zusammengesetzte Primary Key in eine extra Klasse, die Embeddable ist, etwa so:
> 
> ...



So in der Art hatte ich das vor, nur das für die Firma nicht eine Integer-Id verwendet wird sondern die Klasse Firma:


```
@Embeddable
public class KostenstellePK implements Serializable {

    @Column(name = "firmaID")
    private Firma firma;
    @Column(name = "kostenstelleID")
    private Integer kostenstelleID;
}
```


Aber anscheinend kann ich Hibernate nicht mitteilen, das er aus der Klasse Firma sich die Id (Firmennummer,  Integer) besorgen soll um auf die Tabelle zuzugreifen.


```
@Entity
public class Firma implements Serializable{
	
	@Id
	@Column(name="firma_id", nullable=false)
	private int id;
	
	private String bezeichnung;

...
	
}
```


----------



## André Uhres (25. Nov 2010)

Ich denke, dass bei diesem Konzept die Logik zu kurz kommt. Die Firma ist kein Schlüssel, aber KostenstellePK definiert nur einen zusammengesetzten Schlüssel. Da hat die Firma meiner Meinung nach nichts verloren. 

Gruß,
André


----------



## mwr (25. Nov 2010)

André Uhres hat gesagt.:


> Ich denke, dass bei diesem Konzept die Logik zu kurz kommt. Die Firma ist kein Schlüssel, aber KostenstellePK definiert nur einen zusammengesetzten Schlüssel. Da hat die Firma meiner Meinung nach nichts verloren.
> 
> Gruß,
> André



Warum ist die Firma kein Schlüssel? Wir haben mandantenfähige Software (Firma=Mandant). Jede Firma kann ihre eigene Kostenstellen definieren. Somit kann Firma 1 eine Kostenstelle 1 haben und Firma 2 eine Kostenstelle 1 und beide haben unterschiedliche Bedeutungen.

Aus Datenbanksicht ist diese Konstellation nicht ungewöhnliches. Gibt es niemanden hier im Forum, der Hiberante mit einer älteren Datenbank nutzt? Ich habe gehofft Hibernate in einer bestehende Business-Umgebung einsetzen zu können oder ist Hibernate nur etwas für Uni-Schulungsobjekte...?
Es sieht so aus, als muss die Datenbank auf Hibernate bzw. die Objektorientierung von Java ausgerichtet sein.


----------



## maki (25. Nov 2010)

> Aus Datenbanksicht ist diese Konstellation nicht ungewöhnliches.


Nicht ungewöhnlich, aber eben unsauber.



> Ich habe gehofft Hibernate in einer bestehende Business-Umgebung einsetzen zu können oder ist Hibernate nur etwas für Uni-Schulungsobjekte...?


Hibernate bzw. ORM im allgemeinen ist etwas für die Produktion und wird Millionenfach verwendet, aber wenn das Schema schon falsch ist, kann Hibernate auch nicht mehr viel richten... diese Probleme gibt es oft bei Legacy Projekten in denen grobe Fehler gemacht wurden.


----------



## André Uhres (26. Nov 2010)

mwr hat gesagt.:


> Warum ist die Firma kein Schlüssel?



Die Firma ist meiner Meinung nach kein Schlüssel, weil Schlüsselwerte gewöhnlich verwendet werden, um die Eindeutigkeit einer angegebenen Entität zu überprüfen und die Leistung von Abfragen zu verbessern. 

Gemäß diesem Konzept ist die "Firma_ID" der Schlüssel zur Entität "Firma". 

Bei firmenbezogenen Kostenstellen müsste sich demnach der Schlüssel einer Kostenstelle zusammensetzen aus "Firma_ID" und "Kostenstelle_ID".

Gruß,
André


----------



## mwr (29. Nov 2010)

André Uhres hat gesagt.:


> Die Firma ist meiner Meinung nach kein Schlüssel, weil Schlüsselwerte gewöhnlich verwendet werden, um die Eindeutigkeit einer angegebenen Entität zu überprüfen und die Leistung von Abfragen zu verbessern.
> 
> Gemäß diesem Konzept ist die "Firma_ID" der Schlüssel zur Entität "Firma".
> 
> ...



Ok, das habe ich nun verstanden. Ich habe in dem Schlüssel nicht mehr die Firma sondern den Integer-Wert Firma_Id und mappe nun direkt die einzelen Spalten auf den Schlüssel.

Bei der Angabe der ManyToOne-Annotation bekomme ich aber nun eine Fehlermeldung:
"Repeated column in mapping for entity: ft.Kommission column: aefa (should be mapped with insert="false" update="false")"
aefa ist die Firma. aefa ist auch auf die Entity Firma innerhalb der Kommission gemappt. Wenn ich das Mapping der Kostenstelle auf updatable/insertable auf false stelle, funktioniert die Abfrage und die Kostenstelle wird geladen. Aber dann funktioniert das Update der Kostenstelle nicht mehr. Nur die Firma_Id der Kostenstelle auf updatable/insertable zu stellen wird mit einer Exception von Hibernate abgelehnt.

Ich versteht die Diskrepanz beim mappen der Firma, theoretisch könnte die Entität Firma unterschiedlich sein zu der Firma der Entität Kostenstelle (oder der anderen mit Firma angegeben Entitäten). Aber das ist blanke Theorie. Gibt es keine Möglichkeit bei Hibernate dieses abzubilden?


----------

