1. Willkommen im Forum für alle Datenbanken! Registriere Dich kostenlos und diskutiere über DBs wie Mysql, MariaDB, Oracle, Sql-Server, Postgres, Access uvm
    Information ausblenden

Vererbung in OO-Programmierung vs Datenbanken

Dieses Thema im Forum "Datenmodellierung, Datenbank-Design" wurde erstellt von jgsedi, 28 März 2018.

Status des Themas:
Es sind keine weiteren Antworten möglich.
  1. jgsedi

    jgsedi Benutzer

    Hallo Leute,
    ich habe eine generelle Frage: Wie implementiert man in Datenbanken Spezialisierungen - nehmen wir als einfachen Fall den Lehrer und den Schüler als Spezialfall einer Person. (siehe Bild Vererbung-OO-Programmierung.jpg).
    Vererbung-OO-Programmierung.jpg

    Wie setzt man dies nun ganz allgemein in Datenbanken um?

    Erstellt man für Lehrer und Schüler eine Tabelle mit allen Feldern (siehe Schueler-Lehrer.jpg) Schueler-Lehrer.jpg
    oder erstellt man eine Basistabelle und für die Spezialisierungen eigene Tabellen aber nur die fehlenden Felder (siehe Person-Schueler-Lehrer.jpg)?
    Person-Schueler-Lehrer.jpg

    Vielen Dank für eure Mühen
     
  2. akretschmer

    akretschmer Datenbank-Guru

    z.B. kann man das so umsetzen:

    Code:
    test=# create table person(id serial primary key, nachname text, vorname text);
    CREATE TABLE
    test=*# create table schueler (klasse text) inherits (person);
    CREATE TABLE
    test=*# create table lehrer (faecher text[]) inherits (person);
    CREATE TABLE
    test=*# \d+ person
      Tabelle »public.person«
      Spalte  |  Typ  | Sortierfolge | NULL erlaubt? |  Vorgabewert  | Speicherung | Statistikziel | Beschreibung
    ----------+---------+--------------+---------------+------------------------------------+-------------+---------------+--------------
     id  | integer |  | not null  | nextval('person_id_seq'::regclass) | plain  |  |
     nachname | text  |  |  |  | extended  |  |
     vorname  | text  |  |  |  | extended  |  |
    Indexe:
      "person_pkey" PRIMARY KEY, btree (id)
    Kindtabellen: lehrer,
      schueler
    
    test=*# \d+ schueler
      Tabelle »public.schueler«
      Spalte  |  Typ  | Sortierfolge | NULL erlaubt? |  Vorgabewert  | Speicherung | Statistikziel | Beschreibung
    ----------+---------+--------------+---------------+------------------------------------+-------------+---------------+--------------
     id  | integer |  | not null  | nextval('person_id_seq'::regclass) | plain  |  |
     nachname | text  |  |  |  | extended  |  |
     vorname  | text  |  |  |  | extended  |  |
     klasse  | text  |  |  |  | extended  |  |
    Erbt von: person
    
    test=*# \d+ lehrer
      Tabelle »public.lehrer«
      Spalte  |  Typ  | Sortierfolge | NULL erlaubt? |  Vorgabewert  | Speicherung | Statistikziel | Beschreibung
    ----------+---------+--------------+---------------+------------------------------------+-------------+---------------+--------------
     id  | integer |  | not null  | nextval('person_id_seq'::regclass) | plain  |  |
     nachname | text  |  |  |  | extended  |  |
     vorname  | text  |  |  |  | extended  |  |
     faecher  | text[]  |  |  |  | extended  |  |
    Erbt von: person
    
    test=*#
    
     
    Walter gefällt das.
  3. akretschmer

    akretschmer Datenbank-Guru

    Davon abgesehen ist das Modell so nicht gut, ein Lehrer kann ja mehrere Fächer haben / unterrichten. Aber das ist eineandere Baustelle ... (daher auch mein TEXT[] als Datentyp)
     
  4. jgsedi

    jgsedi Benutzer

    Danke @akretschmer , aber ist das Standard - SQL? Ttschuldige, aber ich bin kein Datenbänker und meine Kenntnisse beziehen sich auf einen Informatikkurs aus der Vorzeit! Ein Begriff wie "inherits" ist mir aus SQL nicht bekannt!
    Zur Erklärung: Bei uns geht es um ein Programmierprojekt. Dabei soll SQLite verwendet werden. Dabei kam eben die Grundsatzfrage auf, wie man die OO-Strukturen in DBs abbildet, also auch Vererbung.
     
  5. akretschmer

    akretschmer Datenbank-Guru

    Das ist PostgreSQL. Ist eine Object-relationale Datenbank. Eine recht gute übrigens, kann einiges mehr als die sonstigen und üblichen Verdächtigen. Also nein, ist kein Standard-SQL.
     
  6. jgsedi

    jgsedi Benutzer

    Ach ja, das mit den Lehrern und den Fächern ist klar @akretschmer - aber Danke für den Hinweis.

    Da im Progammierprojekt SQLite erforderlich ist helfen mir Funktionen von spezieller Datenbanksoftware (Postgres, Mysql, ...) nicht. Außerdem geht es hier mehr um das generelle Schema, wie das umsetzbar ist. Mir sind noch ein paar Möglichkeiten eingefallen:

    Mögl 1:
    Create Table Person(ID, Nachname, Vorname)
    Create Table Lehrer(ID {int=Person.ID}, Faecher)
    Create Table Schueler(ID {int=Person.ID}, Klasse)

    Mögl 2:
    Create Table Lehrer(ID, Nachname, Vorname, Faecher)
    Create Table Schueler(ID, Nachname, Vorname, Klasse)

    Mögl 3:
    Create Table Person(ID, Nachname, Vorname)
    Create Table Lehrer(ID, Person_ID {Fkey Person.ID}, Nachname, Vorname, Faecher)
    Create Table Schueler(ID, Person_ID {Fkey Person.ID}, Nachname, Vorname, Klasse)

    oder gar Mögl 4:
    Create Table Person(ID, Nachname, Vorname, Faecher, Klasse)

    oder vielleicht andere Möglichkeiten?

    Wie ihr seht brauch ich wirklich Hilfe ;)
     
    Zuletzt bearbeitet: 28 März 2018
  7. akretschmer

    akretschmer Datenbank-Guru

    am nächsten kommst du dem Ziel, denke ich, mit 1. 3 hat redundante Felder, 4 ist IMHO völlig daneben. Und 2 hat exakt NULL Ansatz für Vererbung. Und wenn Du eine DB ohne Arrays etc. hast solltest Du die Zuordnung Lehrer zu Fächern normalisieren.
     
  8. jgsedi

    jgsedi Benutzer

    Mögl. 1 war auch mein Favorit!

    ABER: Wie ist es dann beim Schreiben der Daten? Gibt es ne Möglichkeit - Trigger - dass man bei der Dateneingabe eine Schülers
    INSERT INTO Schueler(1000, "Mustermann", "Max", "11a")

    die Daten gleich auf beide relevanten Tabellen verteilt
    INSERT INTO Person(1000, "Mustermann", "Max") ++und++ INSERT INTO Schueler(1000, "11a")

    Gibt's/geht so was?
     
  9. akretschmer

    akretschmer Datenbank-Guru

    Beim ersten Insert sollte ja eine ID automatisch generiert werde, und diese dann als FK im zweiten Insert verwendet werden. Die gute Nachricht: das geht alles zusammen in EINEM (in Zahlen: 1) SQL-Statement, un dzwar atomar. Die für Dich vielleicht schlechte: das ist eine PostgreSQL-Erweiterung des SQL-Standards. Nennt sich wCTE: writeable Common Table Expressions.

    Mit anderen Systemen wirst erst den ersten Insert machen müssen und dann mit last_insert_id() oder was das System halt bietet die neue ID ermitteln, um diese beim zweiten Insert verwenden zu können. Transaktionen können helfen, das 'sicher' zu machen.
     
  10. jgsedi

    jgsedi Benutzer

    OK, dann kann ich das bei SQLite vergessen mit "in einem Rutsch"!

    Danke für die prompte Hilfe @akretschmer!
     
  11. akretschmer

    akretschmer Datenbank-Guru

    Offensichtlich ;-)

    um es mal kurz zu zeigen, wie es gehen könnte, würdet ihr die beste OpenSource-Datenbank nutzen:

    Code:
    test=# create table person (id serial primary key, name text);
    CREATE TABLE
    test=*# create table schueler(person_id int references person, klasse text);
    CREATE TABLE
    test=*# with new_id as (insert into person (name) values ('person 1') returning id) insert into schueler select id, 'klasse 1' from new_id;
    INSERT 0 1
    test=*# select * from person;
     id |  name   
    ----+----------
      1 | person 1
    (1 Zeile)
    
    test=*# select * from schueler ;
     person_id |  klasse  
    -----------+----------
      1 | klasse 1
    (1 Zeile)
    
    test=*#
    
    Der Trick ist in:

    Code:
    with new_id as (insert into person (name) values ('person 1') returning id) insert into schueler select id, 'klasse 1' from new_id;
    
    hier wird erst in person eingetragen, die id wird zurück geliefert und in einer virtuellen new_id - Tabelle aufgehoben. Das nachfolgende Insert fragt dann diese Tabelle nach der id ab. Das läßt sich beliebig ausbauen. Stelle Dir das mit dem Lehrer vor und einer Zuordnungstabelle Lehrer <-> Fach. Auch diese könnte man so in einem Rutsch befüllen.
     
  12. drdimitri

    drdimitri Datenbank-Guru

    Moin,
    da hier das Stichwort OO Programmierung genannt wird, ist anzumerken, dass das hier eben keine OO Programmierung ist.
    Hier wird lediglich (pseudo) Vererbung verwendet, und der Kardinalfehler gemacht Objekt und Persistence zu vermischen.

    In der OO Programmierung gibt es Klassen. Klassen haben Konstruktoren, Methoden und Eigenschaften und können Sichtbarkeiten auf diese definieren.
    Das ist in diesem Beispiel nicht der Fall, es werden lediglich Eigenschaften vererbt und zwar mit einer öffentlichen Sichtbarkeit - ebenfalls nicht ganz OO konform.
    In der besten kommerziellen Datenbank :D wird daher zuerst in PLSQL die Klasse samt Konstruktor, Methoden etc. erzeugt, und anschließend in einer Tabelle eine Spalte von diesem Datentyp angelegt.
    Die Persistence ist also getrennt von der eigentlichen Logik innerhalb der Klasse.
     
    akretschmer gefällt das.
  13. akretschmer

    akretschmer Datenbank-Guru

    kannst Du das an einem Beispiel zeigen?
     
  14. drdimitri

    drdimitri Datenbank-Guru

    Sicher.
    Code:
    CREATE OR REPLACE TYPE PERSON AS OBJECT (
    birthday date,
    name varchar2(100),
     
    CONSTRUCTOR FUNCTION person(p_name VARCHAR2,p_birthday DATE) RETURN SELF AS RESULT,
    MEMBER PROCEDURE setName(p_name VARCHAR2),
    MEMBER FUNCTION getName RETURN VARCHAR2,
    MEMBER PROCEDURE setBirthday(p_birthday DATE),
    MEMBER FUNCTION getBirthday RETURN DATE
    );
    
    CREATE OR REPLACE TYPE BODY PERSON AS
    CONSTRUCTOR FUNCTION person(p_name varchar2,p_birthday DATE) RETURN SELF AS RESULT IS
    BEGIN
        setName(p_name);
        setBirthday(p_birthday);
        RETURN;
    END;
    
    MEMBER FUNCTION getName RETURN VARCHAR2 IS
    BEGIN
       RETURN name;
    END;
    
    MEMBER PROCEDURE setName (p_name VARCHAR2) IS
    BEGIN
       name:=p_name;
    END;
    
    MEMBER PROCEDURE setBirthday(p_birthday DATE)IS
    BEGIN
       birthday:=p_birthday;
    END;
    
    MEMBER FUNCTION getBirthday RETURN DATE IS
    BEGIN
       RETURN birthday;
    END;
    
    END;
    Eine einfache Personenklasse mit Konstruktor, getter und setter.
    Jetzt die Tabelle, die die Objekte speichert:

    Code:
    create table t (id number primary key, pers person)
    Und jetzt ein neues Objekt über den Konstruktoraufruf anlegen.
    Code:
    insert into t values (1,person('test1', sysdate-2000));
    Ich würde jedoch von einer ausgiebigen Nutzung davon abraten, insbesondere wenn fachliche Objekte involviert sind.
    Allein die Tatsache, das es für Datenbanken keine IDE vom Kaliber eines Eclipse, IntelliJ oder Visual Studio gibt macht die OO Erweiterungen der Datenbanken eigentlich hinfällig.
    In Ausnahmefällen (z.B. wenn man sich selbst Data Cardridge Erweiterungen schreibt) ist es sicherlich sinnvoll, ansonsten sollte man OO bei den darauf spezialisierten Sprachen belassen.
     
    Walter und akretschmer gefällt das.
Die Seite wird geladen...
Status des Themas:
Es sind keine weiteren Antworten möglich.

Diese Seite empfehlen

  1. Diese Seite verwendet Cookies. Wenn du dich weiterhin auf dieser Seite aufhältst, akzeptierst du unseren Einsatz von Cookies.
    Information ausblenden