# 2 Elterntabellen auf1 Kindtabelle möglich?



## Toni99 (10. Dez 2012)

Hallo liebe Gemeinde,

hoffe ihr könnt mit weiterhelfen. Ich habe viel probiert und gelesen aber ich bekomme es einfach nicht hin. Ich habe 3 Tabellen (Tab1: Firmen, Tab2:Kunden, Tab3:Adressen). Was ich versuche ist das Tab1 und Tab2 beide auf die Adresstabelle Tab3 verweisen und beim Löschen von einem Eintrag in Tab1 oder Tab2 dann auch der entsprechende Eintrag in Tab3 gelöscht wird. Mein Ansatz ist grob unten gezeigt auf weitere Felder in den Tabellen wurde zwecks Übersichtlichkeit verzichtet:

// Tab1
CREATE TABLE Firmen (
    ID VARCHAR (20) NOT NULL,
    PRIMARY KEY (ID)
)

// Tab2
CREATE TABLE Kunden (
    ID VARCHAR (20) NOT NULL,
    PRIMARY KEY (ID)
)

// Tab3
CREATE TABLE Adressen (
    ID VARCHAR (20) NOT NULL,
    PRIMARY KEY (ID),
    FOREIGN KEY (ID) REFERENCES Firmen(ID) ON DELETE CASCADE,
    FOREIGN KEY (ID) REFERENCES Kunden(ID) ON DELETE CASCADE
)

Wenn ich nur einen Fremdschlüssel definiere geht es wie gewünscht doch leider nur für eine der beiden Elternklassen. Jemand eine Idee?

Gruß Toni


----------



## OlliL (10. Dez 2012)

Hallo,

deine Firmen und Kunden haben die gleiche ID wie die Adresse? Warum?

Tabelle Firma:
firmenid, long, not null, PK
adressid, long, not null, FK

Tabelle Kunden:
kundenid, long, not null, PK
adressid, long, not null, FK

Tabelle Adressen:
adressid, long, not null, PK

Eine Delete-Kaskadierung würde ich unterlassen, da nie sichergestellt ist, das Kunde und Firma nicht die gleiche Adresse haben. Den anschliessenden Delete würde ich applikatorisch lösen.

Es geht auch (zummindest bei ORACLE) mit einem AFTER DELETE Trigger sowohl auf Kunden und Firma - dort müsstest du halt sicherstellen, das a) kein anderer Kunde auch diese Adresse hat und b) auch keine andere Firma noch diese Adresse verwendet. Dann könntest du die Adresse löschen.


```
create table firmen (firmenid number(10) not null, adressid number(10) not null);
create table adressen (adressid number(10) not null);
alter table adressen add constraint pk_01 primary key  (adressid);
alter table firmen add constraint pk_02 primary key  (firmenid);
alter table firmen add constraint fk_01 foreign key  (adressid) references adressen (adressid);
create or replace trigger trg_01 after delete on firmen for each row begin delete from adressen where adressid=:old.adressid; end;
/

insert into adressen values (1);
insert into firmen values (1,1);
select * from adressen;

      ADRESSID
--------------
             1

select * from firmen;

      FIRMENID       ADRESSID
-------------- --------------
             1              1

delete from firmen;

1 row deleted.

select * from adressen;

no rows selected
```

Je nachdem was man lieber hat - ich würde mich gegen Trigger aussprechen da es dazu neigt das ganze zu "verstecken".

Die Logik mit einem CASCADE würde nur andersrum funktionieren, wenn du also auf Adressen löscht, dann auch autom. die referenzierten Firmen und Kunden mitzulöschen. Oder willst du sogar genau das?


----------



## Toni99 (10. Dez 2012)

Hallo OlliL,

danke für deine schnelle Antwort. Also die Firma und die Kunden IDs sollten als ID für die Adressen dienen so das jeder Firma oder jedem Kunden genau ein entsprechender Eintrag in der Adresstabelle zugehörig ist und somit auch eindeutig bei einer Delete-Kaskadierung zugeweisen werden kann. Als Beispiel:

Die Tabelle Firma hat 2 Einträge:

Eintrag1 --> Firma1 (ID)
Eintrag2 --> Firma2 (ID)

Die Tabelle Kunde hat 1 Eintrag:

Eintrag1 --> Kunde1 (ID)

Die Tabelle Adresse sollte nun enthalten:

Firma1 (ID), PLZ, ORT, STRASSE, ...
Firma2 (ID), PLZ, ORT, STRASSE, ...
Kunde1 (ID), PLZ, ORT, STRASSE, ...

Wenn ich nun Eintrag1 aus Tabelle Firma löschen will dann dachte ich das wenn ein Fremdschlüssel auf der Tabelle Adresse gelegt ist dann auch gleichzeitig dieser Eintrag gelöscht wird. In der Anwendung will ich nur Firmen oder Kunden einzeln löschen aber keine Adressen.

Dein Beispiel werd ich mal einbauen und testen ... Danke schonmal!


----------



## OlliL (10. Dez 2012)

Hallo,

wenn du das wirklich so machen möchtest von der Modellierung her, wäre mein Vorschlag du drehst die Fremdschluesselbeziehungen um.

Also mit deinem Beispiel:

// Tab1
CREATE TABLE Firmen (
ID VARCHAR (20) NOT NULL,
PRIMARY KEY (ID)
FOREIGN KEY (ID) REFERENCES Adressen(ID) ON DELETE CASCADE,
)

// Tab2
CREATE TABLE Kunden (
ID VARCHAR (20) NOT NULL,
PRIMARY KEY (ID)
FOREIGN KEY (ID) REFERENCES Adressen(ID) ON DELETE CASCADE,
)

// Tab3
CREATE TABLE Adressen (
ID VARCHAR (20) NOT NULL,
PRIMARY KEY (ID),
)

Bedeutet nun natürlich, das immer erst Adressen angelegt werden müssen, und dann Kunden/Firmen mit dem gleichen Schluessel.

Wenn ich das Modell bewerten darf, wuerde ich zu einer extra Adressverknüpfung raten und nicht die gleichen IDs verwenden. Vor allem wenn du von Firmen/Kunden in Richtung Adressen gehst, musst du ja immer sicherstellen, das es keine ID-Überschneidungen gibt durch Präfixe in der ID oder irgend ein anderes Konzept... finde ich etwas unsauber. Je nach DB würde ich versuchen weitestgehend technisch generierte Schluessel via Sequence oder "Auto Increment" vorziehen sofern der Schluessel nicht gleichzeitig eine fachliche Relevanz hat und nach einem bestimmten Schema aufgebaut sein muss. Das ist aber nur meine persoenliche Meinung und tut nicht viel zur Problemloesung bei


----------



## Toni99 (10. Dez 2012)

Hallo,

so wie dein Vorschlag war, mit dem Umdrehen der Fremdschluesselbeziehungen, hab ich es versucht aber das hatte leider beim löschen eines Firmeneintrages oder Kundeneintrages keine Auswirkung auf den Eintrag in den Adressen via Kaskadierung.

Ich nutze HSQLDB und würde lieber selbstgenerierte Schlüssel nehmen nur leider habe ich dann keine Idee wie ich an die Schlüssel komme wenn ich einen Eintrag hinzugefügt habe. 

Die Kunden sind überschaubar gering und werden intern im Hause über ihre Acronyme (MaxMustermann = MM, etc.) eindeutig bestimmt genauso wie die Firmen von daher denke ich würde die unsaubere Lösung auch funktionieren.

"Wenn ich das Modell bewerten darf, wuerde ich zu einer extra Adressverknüpfung raten und nicht die gleichen IDs verwenden." wie meinst du das? Eine Spalte mit einer extra adress-ID? Nur wie weiße ich dann dem Kunden/Firma die gerade generierte ID zu?


----------



## OlliL (10. Dez 2012)

Hallo,

Bzgl. dem verwenden einer extra Adress-ID aus meinem Datenmodellvorschlag:
ich kenne jetzt HSQLDB nicht, aber die automatisch vergebene Id sollte nach deinem .persist(Objekt) in dem Objekt drin
stehen da diese von Hibernate nachträglich eingetragen wird nach dem INSERT.
Du könntest nach dem .persist() deiner Adresse, dieses Objekt einfach deinem Firmen-Objekt oder deinem Kunden-Objekt zuweisen und dann das persist des Firmen/Kunden-Objektes machen.

Irgendwie sowas in der Art:


```
@Entity(name = "Firmen")
public class Firma implements Serializable {
	@OneToOne()
	@JoinColumn(name = "adressid", referencedColumnName = "adressid")
	private Adresse adresse;
....
```


```
.persist(adresse);
firma.setAdresse(adresse);
.persist(firma);
```


----------

