+ All Categories
Home > Documents > Objektrelationales Mapping mit JPA Beziehungen Jonas Bandi Simon Martinelli.

Objektrelationales Mapping mit JPA Beziehungen Jonas Bandi Simon Martinelli.

Date post: 05-Apr-2015
Category:
Upload: maud-lasser
View: 105 times
Download: 0 times
Share this document with a friend
18
Objektrelationales Mapping mit JPA Beziehungen Jonas Bandi Simon Martinelli
Transcript
Page 1: Objektrelationales Mapping mit JPA Beziehungen Jonas Bandi Simon Martinelli.

Objektrelationales Mapping mit JPA

Beziehungen

Jonas BandiSimon Martinelli

Page 2: Objektrelationales Mapping mit JPA Beziehungen Jonas Bandi Simon Martinelli.

Eine Parent-Child Beziehung

Wie sieht das Klassen-Modell aus?

– Employee hat eine Referenz auf Department

– Department hat eine Collection von Employee Referenzen

– Beides: Bidirektionale Beziehung

Unabhängig davon ist das zugrundeliegende DB-Schema:

Page 3: Objektrelationales Mapping mit JPA Beziehungen Jonas Bandi Simon Martinelli.

Eine Parent-Child Beziehung

Mapping des Klassenmodells auf das DB-Schema mittels JPA: Metadata ist erforderlich.

– Je nach Klassenmodell wird entweder eine many-to-one Beziehung oder eine one-to-many Beziehung gemappt

– Falls beide Richtungen gemappt werden sollen, so muss definiert werden, dass für beide derselbe Foreign-Key zugrunde liegt.

Page 4: Objektrelationales Mapping mit JPA Beziehungen Jonas Bandi Simon Martinelli.

Eine Parent-Child Beziehung

@Entitypublic class Employee { … @ManyToOne private Department department; …

@Entitypublic class Department { … @OneToMany @JoinColumn (name=”department_id”) private Set<Employee> employees =

new HashSet<Employee>(); …

@Entitypublic class Department { … @OneToMany (mappedBy = “department“) private Set<Order> employees =

new HashSet<Employee>(); …

Mapping der one-to-many Beziehung• Field/Property muss ein Interface sein• Achtung:– Mapping entspricht nicht JPA-Standard! – Unidirektionales one-to-many ohne

Beziehungstabelle wird erst ab JPA2 unterstützt– Jedoch: Konkrete JPA-Implementationen

unterstützen es bereits

Mapping der many-to-one Beziehung

Mapping der bidirektionalen Beziehung

• JPA muss wissen, dass nur ein Foreign-Key für beide Richtungen existiert.

Page 5: Objektrelationales Mapping mit JPA Beziehungen Jonas Bandi Simon Martinelli.

Collection Types• Richtung

– Unidirektional

– Bidirektional

• Kardinalität

– One-to-one

– Many-to-one

– One-to-many

– many-to-many

Employee Project

Employee Address

Source Target

Employee Department* 1

Employee Project* *

Employee Address1 1

Employee Phone1 *

Page 6: Objektrelationales Mapping mit JPA Beziehungen Jonas Bandi Simon Martinelli.

one-to-one, unidirektional

Employee

@OneToOneprivate Address address;

entspricht:

@OneToOne@JoinColumn(name="address_id", referencedColumnName = "id")private Address address;

-id : int-name : String-salary : long

Employee

-id : int-street : String-city : String-state : String-zip : String

Address

0..1

ADDRESS

ID

CITY (O) STATE (O) STREET (O) ZIP (O)

EMPLOYEE

ID

NAME (O) SALARY (O) STARTDATE (O) DEPARTMENT_ID (O) (FK)MANAGER_ID (O) (FK)ADDRESS_ID (O) (FK)

Page 7: Objektrelationales Mapping mit JPA Beziehungen Jonas Bandi Simon Martinelli.

many-to-one, unidirektional

-id : int-name : String-salary : long

Employee

-id : int-name : String

Department

* 0..1

DEPARTMENT

ID

NAME (O)

EMPLOYEE

ID

NAME (O) SALARY (O) STARTDATE (O) DEPARTMENT_ID (O) (FK)MANAGER_ID (O) (FK)ADDRESS_ID (O) (FK)

DEPARTMENT

ID

NAME (O)

EMPLOYEE

ID

NAME (O) SALARY (O) STARTDATE (O) DEPARTMENT_ID (O) (FK)MANAGER_ID (O) (FK)ADDRESS_ID (O) (FK)

DEPARTMENT

ID

NAME (O)

EMPLOYEE

ID

NAME (O) SALARY (O) STARTDATE (O) DEPARTMENT_ID (O) (FK)MANAGER_ID (O) (FK)ADDRESS_ID (O) (FK)

Employee@ManyToOneprivate Department department;

Page 8: Objektrelationales Mapping mit JPA Beziehungen Jonas Bandi Simon Martinelli.

one-to-many, bidirektional

Phone

@ManyToOne(optional = false)private Employee employee;

Employee

@OneToMany(mappedBy = "employee")private Collection<Phone> phones;

-id : int-phonenumber : String-type : String

Phone

-id : int-name : String-salary : long

Employee

* 1

EMPLOYEE

ID

NAME (O) SALARY (O) STARTDATE (O) DEPARTMENT_ID (O) (FK)MANAGER_ID (O) (FK)ADDRESS_ID (O) (FK)

PHONE

ID

PHONENUMBER (O) TYPE (O) EMPLOYEE_ID (O) (FK)

Page 9: Objektrelationales Mapping mit JPA Beziehungen Jonas Bandi Simon Martinelli.

many-to-many, bidirektional

Employee

@ManyToMany(mappedBy = "employees")

private Collection<Project> projects;

Project

@ManyToMany

private Collection<Employee> employees;

-id : int-name : String-salary : long

Employee

-id : int-name : String

Project

* *

PROJECT

ID

DTYPE (O) NAME (O)

PROJECT_EMPLOYEE

PROJECTS_ID (FK)EMPLOYEES_ID (FK)

EMPLOYEE

ID

NAME (O) SALARY (O) STARTDATE (O) DEPARTMENT_ID (O) (FK)MANAGER_ID (O) (FK)ADDRESS_ID (O) (FK)

Page 10: Objektrelationales Mapping mit JPA Beziehungen Jonas Bandi Simon Martinelli.

Many-To-Many Beziehungen

„If you think that two objects share a simple many-to-many relationship, you haven't looked closely enough at the domain. There is a third object waiting to be discovered with attributes and a life cycle all its own.“

- Dierk König

• Oft sind weitere Daten auf der Zwischentabelle nötig

• Üblicherweise mappt man dann die Zwischentabelle auf eine eigene Entity

Page 11: Objektrelationales Mapping mit JPA Beziehungen Jonas Bandi Simon Martinelli.

one-to-many, unidirektional• Bei einer unidirektionalen one-to-many Beziehungen fehlt das

mappedBy Element und das Target hat keine Rückbeziehung

• JPA verwendet in diesen Fällen ebenfalls eine Beziehungstabelle

• JPA 2 spezifiziert die unidirektionale one-to-many Beziehung ohne Zwischentabelle. Etliche JPA Provider unterstützen dies bereits heute.

@OneToMany@JoinColumn (name=”department_id”)private Set<Employee> employees = new HashSet<Employee>();

@OneToManyprivate Set<Employee> employees = new HashSet<Employee>();

Page 12: Objektrelationales Mapping mit JPA Beziehungen Jonas Bandi Simon Martinelli.

Bidirektionale Beziehungen

JPA verändert die Java-Semantik nicht!

D.h. der korrekte Unterhalt von bidirektionalen Beziehungen ist Sache der Applikation!

Department taxes = new Department();

Employee john = new Employee();

taxes.getEmployees().add(john);

john.setDepartment(taxes);

Page 13: Objektrelationales Mapping mit JPA Beziehungen Jonas Bandi Simon Martinelli.

Bidirektionale BeziehungenBest Practice: Convenience Methoden auf den Entities:@Entitypublic class Department { … @OneToMany private List<Employee> employees = new ArrayList<Employee>();

public void addEmployee(Employee employee){ if (employee == null)

throw new IllegalArgumentException(“Null employee“); if (employee.getDepartment() != null) employee.getDepartment().getEmployees().remove(employee); getEmployees().add(employee); employee.setDepartment(this); } …}

Analog: removeEmployee() sowie Methoden auf Employee.

Page 14: Objektrelationales Mapping mit JPA Beziehungen Jonas Bandi Simon Martinelli.

Verwendung von Collections• java.util.Set

– Eindeutig (Object.equals())– @OneToManyprivate Set<Phone> phones;

• java.util.List– geordnet, kann sortiert werden– @OneToMany@OrderBy("phonenumber ASC")private List<Phone> phones;

• java.util.Map– Key/Value Paare– @OneToMany@MapKey(name = "phonenumber")private Map<String, Phone> phones;

JPA 2:Persistenter Index@OneToMany@OrderColumn(name="index")private List<Phone> phones;

Page 15: Objektrelationales Mapping mit JPA Beziehungen Jonas Bandi Simon Martinelli.

Lazy- und Eager-Loading

• Default bei one-to-one und many-to-one– FetchType.EAGER

• Default bei one-to-many und many-to-many– FetchType.LAZY

• Defaultverhalten kann übersteuert werden. z.B.– @OneToMany(fetch = FetchType.EAGER)private Set<Phone> phones;

EntityManager em = ...Department foreignAffairs = em.find(Department.class, 123);foreignAffairs.getEmployees().iterator().next();

Beziehungen werden transparent (nach)geladen:

Page 16: Objektrelationales Mapping mit JPA Beziehungen Jonas Bandi Simon Martinelli.

Speichern und Löschen von Beziehungen

Department taxes = new Department();Employee john = new Employee();taxes.addEmployee(john);Employee jane = new Employee();taxes.addEmployee(jane);

em.persist(taxes);em.persist(john);em.persist(jane);em.flush();

for (Employee empl : taxes.getEmployees()){ em.remove(empl);}em.remove(taxes);em.flush();

• Jede Entity hat einen eigenen, unabhängigen Lifecycle!

• IllegalStateException wenn vergessen wird, eine assoziierte Entity zu persistieren.

• Delete all entities individually

Page 17: Objektrelationales Mapping mit JPA Beziehungen Jonas Bandi Simon Martinelli.

Transitive Persistenz

Persistenz wird von JPA propagiert auf assoziierte Entities.

@OneToMany (mappedBy = “department“, cascade = CascadeType.ALL)

private Set<Employee> employees = new HashSet<Employee>();

Department taxes = new Department();Employee john = new Employee();taxes.addEmployee(john);Employee jane = new Employee();taxes.addEmployee(jane);

em.persist(taxes);em.flush();

em.delete(taxes);em.flush();

• Kaskadierung wird auf der Assoziation konfiguriert

• Speichern eines Parents speichert auch alle Kinder

• Löschen eines Parents löscht auch alle Kinder.

CascadeType {ALL, PERSIST, MERGE, REMOVE, REFRESH, DETACH};

Page 18: Objektrelationales Mapping mit JPA Beziehungen Jonas Bandi Simon Martinelli.

Orphan DeletionPhone phone1 = …Employee john = em.find(Employee.class, 123);john.getPhones().remove(phone1);em.flush();

• Child wird nicht gelöscht!

Entfernen eines Kindes aus der Collection des Parents setzt nur den Foreign Key auf der Kind-Tabelle auf NULL.

– FK Constraint Verletzung möglich– Das Kind ist nun “orphaned”

• JPA kann Orphans nicht automatisch löschen, dies muss explizit in der Applikation erfolgen.

• Proprietäre Mechanismen von JPA-Providers erlauben bereits das automatische Löschen von Orphans

• JPA 2 unterstützt das automatische Löschen von Orphans

• Child wird nicht gelöscht!

@OneToMany(cascade=ALL, mappedBy=”customer”, orphanRemoval=true) public Set<Order> getOrders() { return orders; }


Recommended