Objektrelationale Abbildungen

Relationale Datenbanken als persistenter Speicher

Grundsätzliches

  • Pluspunkte
    • Weit verbreitet, sehr zuverlässig
    • sehr gute open source Datenbanken verfügbar
    • Firmen haben sehr viel Geld in Software und Ausbildung investiert
    • Daten sind ein sehr wichtiger Besitz von Firmen
      • Kundendaten, Produktdaten, Mitarbeiter
      • Daten „leben“ sehr lange (20 Jahre und mehr)
      • keine Bereitschaft, Datenbanksysteme zu wechseln
  • Nachteil
    • Relationale Datenbanken passen nicht optimal zur objektorientierten Programmierung
      • manche Objektstrukturen nicht effizient abbildbar → CAD-Systeme, Social Media …
  • In der Praxis
    • Objekt-relationale Abbildungen sind weit verbreitet
    • bei typischer Enterprise Software gut brauchbar
      • Es gibt eine gute Unterstützung durch Programmbibliotheken bei JEE und Spring
      • Spring und JEE verwenden die Java Persistence API (JPA)
      • Spring verwendet standardmäßig das open source Framework Hibernate
    • Non-SQL-Datenbanken gewinnen an Bedeutung
    • OODBMS sind kaum im Einsatz

Objektrelationale Abbildungen

  1. Persistente Klassen
    Scrum UML Modell mir ORM Annotationen
    ORM im Beispielmodell
    • Jede Klasse wird in einer eigenen Tabelle dargestellt.
    • Die Objektidentität wird durch einen synthetischen Schlüssel sichergestellt.
    • Attribute werden wenn möglich als Spalten der Tabelle dargestellt.
    • Attribute mit einem Klassentyp, die nicht direkt durch einen SQL-Datentyp abgebildet werden können, werden in eigene Tabellen abgebildet.
  2. Assoziationen
    • 1:1 und 1:n Assoziation → Darstellung als Fremdschlüssel in der Datenbank.
    • m:n Assoziation → Darstellung als Korrelationstabelle in der Datenbank.
  3. Vererbung
    • 3 Varianten der Realisierung:
      • Eine Tabelle pro Klassenhierarchie,
      • eine Tabelle pro konkreter Klasse,
      • eine Tabelle pro Klasse.

Realisierung im Code mit JPA Annotationen

  • Klassen, die nicht in einer Vererbungshierarchie eingebunden sind (außer mit Object)
    • Soll Klasse in die Datenbank abgeildet werden → @Entity
    • Soll ein bestimmter Tabellenname verwendet werden → @Table( … )
      • für Nameskonventionen (z.B. alle Tabellennamen fangen mit TBL_ an)
      • Vermeiden reservierter Wörter (z.B. Union)
      • default: Klassenname = Tabellenname

  • Attribute
    • Jede Klasse braucht einen Primärschlüssel
      • Empfohlen: semantikfreies Schlüsselattribut (sog. surrogate key)
      • möglichst Schlüsselerzeugungsmechanismus des DBMS nutzen
    • Zugriff auf Attribute: field | method
      • wird als default durch Position der @Id Annotation bestimmt:
        • vor Feld → field, vor getter → method
        • kann individuell geändert werden
        • JPA/Hibernate greift auch auf private Elemente zu (Bytecode Manipulation)
    • Komplexe Attribute
      • Kompositionsbeziehung: Objekt wird in der Tabelle des besitzenden Objekts mit abgelegt
        • @Embedded Annotation vor Attribut oder @Embeddable Annotation vor der Klassendefinition des Attributs
      • Assoziationen werden anders behandelt!
    • Attribute, die nicht persistiert werden sollen, werden mit @Transient annotiert
  • Assoziationen
    • Assoziationen in JPA sind immer unidirektional, Beziehungen in einer relationalen Datenbank sind immer bidirektional abfragbar
    • Wenn die Assoziation in Java bidirektional implementiert ist, muss das durch mappedBy angezeigt werden
    • Synchronisation der Assoziationsenden in Java muss im Java-Code erfolgen
      • Beispiel 1 : n Beziehung: @JoinColumn definiert die Fremdschlüsselspalte
        	@ManyToOne
        	@JoinColumn(name="Project_ID", nullable=false)
        	private Project project;
        	@OneToMany(mappedBy = "project")
        	private Set<Sprint> ssprint = new HashSet<Sprint>();
      • Beispiel m : n Beziehung:
        @JoinTable definiert die Link-Tabelle mit Tabellenname und Spaltennamen

        	@ManyToMany
        	@JoinTable(name = "link_Sprint_Task",
        		joinColumns = { @JoinColumn(name = "task_id") },
        		inverseJoinColumns = { @JoinColumn(name = "sprint_id") }
        	)
        	private Set<Sprint> sprint= new HashSet<Sprint>();
        
        	@ManyToMany(mappedBy="backlog")
        	private Set<Task> members = new HashSet<Task>();
        
    • Kaskadierung: Einfüge- und Löschoperationen können über Assoziationen hinweg auf die Objekte wirken
      • Reduziert die Anzahl der save() bzw. delete-Aufrufe
      • kann mit Hilfe der Annotationen definiert werden
      • Hibernate-Annotationen sind weitergehend als JPA Annotationen
      • Beispiel:
        	@ManyToMany
        	@JoinTable(name = "link_Sprint_Task",
        		joinColumns = { @JoinColumn(name = "task_id") },
        		inverseJoinColumns = { @JoinColumn(name = "sprint_id") }
        	)
        	@Cascade(org.hibernate.annotations.CascadeType.SAVE_UPDATE);
        	private Set<Sprint> sprint= new HashSet<Sprint>();
        
  • Klassenhierarchien, Vererbung
    • Drei unterschiedliche Strategien zur Abbildung der Objekte auf Tabellen:
      SINGLE_TABLE | JOINED | TABLE_PER_CLASS
    • Angabe in der obersten Basisklasse gilt für alle Subklassen
    • screenshot bei single table inheritanceStrategie Single Table: Alle Klassen einer Vererbungshierarchie in einer Tabelle
      • Performant, Polymorphismus einschließlich polymorpher Assoziationen einfach zu realisieren
      • Verstoß gegen 3. Normalform
      • Spalten von Kindklassen müssen nullable sein
      @Entity
      @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
      @DiscriminatorColumn(name="DTYPE",
              discriminatorType=DiscriminatorType.STRING) // optional
      public abstract class Task {
          @Id
          @GeneratedValue(strategy = GenerationType.AUTO)
          private Long id;
      
      select * from task
    • screenshot bei joined inheritanceStrategie Joined: Kindklassentabellen werden über Fremdschlüssel mit der Basisklasse verknüpft
      • 3. Normalform ok, not null constraints möglich
      • kleiner Performancenachteil, da auf mehrere Tabellen zugegriffen werden muss
      • komplexere SQL Queries (nur bei direktem DB-Zugriff, nicht aus Java)
      @Entity
      @Inheritance(strategy = InheritanceType.JOINED)
      public abstract class Task {
          @Id
          @GeneratedValue(strategy = GenerationType.AUTO)
          private Long id;
      
      select * from task natural join compound_task
    • Strategie Table per Class: Jede nichtabstrakte Klasse hat eigene Tabelle
      • Probleme mit Polymorphismus, nicht empfehlenswert
      • Lässt sich für das Beispielprojekt daher nicht ohne größere Änderungen demonstrieren

Aufgabe

Implementieren Sie die von Ihnen zum Klassenmodell hinzugefügten Domainklassen mit den für die persistente Speicherung notwendigen JPA Annotationen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.