Odwzorowanie relacji

Komentarze

Transkrypt

Odwzorowanie relacji
Relacje
1. Modelowanie relacji.
- siedem rodzajów relacji J2EE.
- relacje jedno i wielokierunkowe,
- relacje reprezentowane przez kolekcje.
1
Relacje
Modelowanie pojęć biznesowych wymaga łączenia komponentów encyjnych
w relacje. Specyfikacja JEE określa siedem rodzajów relacji: jeden-do-jednego
(one-to-one), jeden-do-wielu (one-to-many), wiele-do-jednego (many-to-one)
oraz wiele-do-wielu (many-to-many). Relacja może mieć charakter
jednokierunkowy (unidirectional) lub dwukierunkowy (bidirectional).
2
Jednokierunkowa relacja 1:1
CUSTOMER
ADDRESS
ID
FIRST_NAME
LAST_NAME
...
ADDRES_ID
ID
STREET
CITY
ZIP
...
1
1
@Entity
public class Customer implements java.io.Serializable {
...
private Address address;
...
@OneToOne(cascade={CascadeType.ALL})
@JoinColumn(name="ADDRESS_ID")
public Address getAddress( ) {
return address;
}
...
}
3
Jednokierunkowa relacja 1:1
<entity-mappings>
<entity class="com.titan.domain.Customer" access="PROPERTY">
<attributes>
<id name="id">
<generated-value/>
</id>
<one-to-one name="address"
targetEntity="com.titan.domain.Address"
fetch="LAZY" optional="true">
<cascade>ALL</cascade>
<join-column name="ADDRESS_ID"/>
</one-to-one>
</attributes>
</entity>
</entity-mappings>
4
Złączenie wg. klucza
głównego
...
@OneToOne
@PrimaryKeyJoinColumn(cascade={CascadeType.ALL})
public Address getAddress( ) {
return address;
}
...
Kontener automatycznie zmodyfikuje tabelę CUSTOMER:
CREATE TABLE CUSTOMER(
ID INT PRIMARY KEY NOT NULL,
address_id INT,
...
)
ALTER TABLE CUSTOMER ADD CONSTRAINT customerREFaddress
FOREIGN KEY (address_id) REFERENCES ADDRESS (id);
5
Dwukierunkowa relacja 1:1
CUSTOMER
CREDIT_CARD
ID
FIRST_NAME
LAST_NAME
...
CREDIT_CARD_ID
ID
NUMBER
EXP_DATE
...
1
1
Relacja dwukierunkowa polega na tym, ze jeden obiekt (encja) otrzymuje
referencję do drugiego obiektu (encji) oraz drugi obiekt posiada referencję do
pierwszego. Relacje dwukierunkowe są odwzorowane w relacyjnym modelu
danych identycznie jak relacje jednokierunkowe.
6
Dwukierunkowa relacja 1:1
@Entity
public class CreditCard implements java.io.Serializable {
private Customer customer;
...
// nazwa atrybutu w klasie Customer, którego dotyczy mapowanie
@OneToOne(mappedBy="creditCard")
public Customer getCustomer( ) { return this.customer; }
...
}
Klasa Customer nie ulega zmianie w porównaniu z relacją jednokierunkową
@Entity
public class Customer implements java.io.Serializable {
private CreditCard creditCard;
...
@OneToOne(cascade={CascadeType.ALL})
@JoinColumn(name="CREDIT_CARD_ID")
public CreditCard getCreditCard( ) {
return creditCard; }
...
}
7
Dwukierunkowa relacja 1:1
Przykład programu wiążącego encje Customer oraz CreditCard:
Customer cust = new Customer( );
CreditCard card = new CreditCard( );
cust.setCreditCard(card);
card.setCustomer(cust);
entityManager.persist(cust);
Ponieważ w adnotacji OneToOne encji Customer ustawiliśmy atrybut
cascade={CascadeType.ALL} odpowiedni wpis w tabeli CREDIT_CARD
zostanie utworzony automatycznie.
8
Strona właścicielska
i przeciwna
Ustawione w powyższy sposób odwzorowanie określa, że obiekt Customer
jest stroną właścicielską (owning side) natomiast CreditCard stroną
przeciwną (inverse side). Poprawna zmiana właściciela karty kredytowej musi
odbywać się następująco:
Customer newCust = em.find(Customer.class, newCustId);
CreditCard card = oldCustomer.getCreditCard( );
oldCustomer.setCreditCard(null);
newCust.setCreditCard(card);
natomiast jej usunięcie jest realizowane przez:
Customer cust = em.find(Customer.class, id);
em.remove(cust.getCreditCard( ));
cust.setCreditCard(null);
9
Dwukierunkowa relacja 1:1
<entity-mappings>
<entity class="com.titan.domain.Customer" access="PROPERTY">
...
</entity>
<entity class="com.titan.domain.CreditCard" access="PROPERTY">
<attributes>
<id name="id">
<generated-value/>
</id>
<one-to-one name="customer"
target-entity="com.titan.domain.Customer"
mapped-by="creditCard"/>
</attributes>
</entity>
</entity-mappings>
10
Jednokierunkowa relacja 1:N
CUSTOMER
PHONE
ID
FIRST_NAME
LAST_NAME
...
ID
NUMBER
TYPE
...
CUSTOMER_ID
1
N
@Entity
public class Customer implements java.io.Serializable {
...
private Collection<Phone> phoneNumbers = new
ArrayList<Phone>( );
...
@OneToMany(cascade={CascadeType.ALL})
@JoinColumn(name="CUSTOMER_ID")
public Collection<Phone> getPhones( ) {
return phoneNumbers;
}
...
}
11
Jednokierunkowa relacja 1:N
Obsługa encji jest analogiczna jak w przypadku jednokierunkowej relacji jedendo-jednego.
Customer cust = entityManager.find(Customer.class, pk);
Phone phone = new Phone("123-456-7890");
// dodanie telefonu
cust.getPhones( ).add(phone);
// usunięcie telefonu
cust.getPhones( ).remove(phone);
entityManager.remove(phone);
12
Jednokierunkowa relacja 1:N
<entity-mappings>
<entity class="com.titan.domain.Customer" access="PROPERTY">
<attributes>
<id name="id">
<generated-value/>
</id>
<one-to-many name="phones"
targetEntity="com.titan.domain.Phone">
<cascade-all/>
<join-column name="CUSTOMER_ID"/>
</one-to-many>
</attributes>
</entity>
</entity-mappings>
13
Relacja z wykorzystaniem
tabeli złączenia
CUSTOMER
ID
FIRST_NAME
LAST_NAME
...
PHONE
CUSTOMER_PHONE
1 N
CUSTOMER_ID
PHONE_ID
N 1
ID
NUMBER
TYPE
...
@Entity
public class Customer implements java.io.Serializable {
...
private Collection<Phone> phones;
...
@OneToMany(cascade={CascadeType.ALL})
@JoinTable(name="CUSTOMER_PHONE"),
joinColumns={@JoinColumn(name="CUSTOMER_ID")},
inverseJoinColumns={@JoinColumn(name="PHONE_ID")})
public Collection<Phone> getPhoneNumbers( ) { return phones; }
...
}
14
Relacja z wykorzystaniem
tabeli złączenia
<entity-mappings>
<entity class="com.titan.domain.Customer" access="PROPERTY">
<attributes>
<id name="id">
<generated-value/>
</id>
<one-to-many name="phones"
targetEntity="com.titan.domain.Phone">
<cascade-all/>
<join-table name="CUSTOMER_PHONE">
<join-column name="CUSTOMER_ID"/>
<inverse-join-column name="PHONE_ID"/>
</join-table>
</one-to-many>
</attributes>
</entity>
</entity-mappings>
15
Jednokierunkowa relacja N:1
CRUISE
ID
NAME
...
SHIP_ID
SHIP
N
1
ID
NAME
...
@Entity
public class Cruise implements java.io.Serializable {
private Ship ship;
...
@ManyToOne
@JoinColumn(name="SHIP_ID")
public Ship getShip( ) { return ship; }
...
}
16
Jednokierunkowa relacja N:1
<entity-mappings>
<entity class="com.titan.domain.Cruise" access="PROPERTY">
<attributes>
<id name="id">
<generated-value/>
</id>
<many-to-one name="ship"
target-entity="com.titan.domain.Ship" fetch="EAGER">
<join-column name="SHIP_ID"/>
</many-to-one>
</attributes>
</entity>
</entity-mappings>
17
Dwukierunkowa relacja 1:N
CRUISE
RESERVATION
ID
NAME
SHIP_ID
...
ID
AMOUNT_PAID
...
CRUISE_ID
1
N
Analogicznie jak w poprzednim wypadku relacja dwukierunkowa jest
wykorzystywana gdy obie encje muszą „wiedzieć” o sobie nawzajem. W modelu
programistycznym odpowiednie adnotacje są dodane do definicji obu klas. Zgodnie
ze specyfikacją JPA stroną właścicielską jest komponent naprzeciwko encji
z licznością równą jeden. W naszym przypadku to Reservation.
18
Dwukierunkowa relacja 1:N
@Entity
public class Reservation implements java.io.Serializable {
private Cruise cruise;
...
@ManyToOne
@JoinColumn(name="CRUISE_ID")
public Cruise getCruise( ) { return cruise; }
...
}
@Entity
public class Cruise implements java.io.Serializable {
...
private Collection<Reservation> reservations = new
ArrayList<Reservation>( );
...
@OneToMany(mappedBy="cruise")
public Collection<Reservation> getReservations( ) {
return reservations;
}
...
}
19
Dwukierunkowa relacja 1:N
<entity-mappings>
<entity class="com.titan.domain.Cruise" access="PROPERTY">
<attributes>
<id name="id"><generated-value/></id>
<one-to-many name="ship"
target-entity="com.titan.domain.Reservation"
fetch="LAZY" mapped-by="cruise">
</one-to-many>
</attributes>
</entity>
<entity class="com.titan.domain.Reservation" access="PROPERTY">
<attributes>
<id name="id"><generated-value/></id>
<many-to-one name="cruise"
target-entity="com.titan.domain.Cruise"
fetch="EAGER">
<join-column name="CRUISE_ID"/>
</many-to-one>
</attributes>
</entity>
</entity-mappings>
20
Dwukierunkowa relacja N:N
CUSTOMER
ID
FIRST_NAME
LAST_NAME
...
RESERVATION
CUSTOMER_RESERVATION
CUSTOMER_ID
RESERVATION_ID
ID
AMOUNT_PAID
...
Relacja wiele-do-wielu w relacyjnym modelu danych odwzorowana
z wykorzystaniem tabeli złączenia
21
Dwukierunkowa relacja N:N
@Entity
public class Reservation implements java.io.Serializable {
private Set<Customer> customers = new HashSet<Customer>( );
...
@ManyToMany
@JoinTable(name="RESERVATION_CUSTOMER"),
joinColumns={@JoinColumn(name="RESERVATION_ID")},
inverseJoinColumns={@JoinColumn(name="CUSTOMER_ID")})
public Set<Customer> getCustomers( ) { return customers; }
...
}
@Entity
public class Customer implements java.io.Serializable {
private Collection<Reservation> reservations = new
ArrayList<Reservation>( );
...
@ManyToMany(mappedBy="customers")
public Collection<Reservation> getReservations( ) {
return reservations;
}
}
22
Dwukierunkowa relacja N:N
<entity-mappings>
<entity class="com.titan.domain.Reservation" access="PROPERTY">
<attributes><id name="id"><generated-value/></id>
<many-to-many name="customers"
target-entity="com.titan.domain.Customer" fetch="LAZY">
<join-table name="RESERVATION_CUSTOMER">
<join-column name="RESERVATION_ID"/>
<inverse-join-column name="CUSTOMER_ID"/>
</join-table>
</many-to-many>
</attributes>
</entity>
<entity class="com.titan.domain.Customer" access="PROPERTY">
<attributes><id name="id"><generated-value/></id>
<many-to-many name="cruise"
target-entity="com.titan.domain.Reservation"
fetch="LAZY" mapped-by="customers">
</many-to-many>
</attributes>
</entity>
</entity-mappings>
23
Jednokierunkowa relacja N:N
CABIN
ID
NAME
DECK
...
RESERVATION
CABIN_RESERVATION
CABIN_ID
RESERVATION_ID
ID
AMOUNT_PAID
...
@Entity
public class Reservation implements java.io.Serializable {
...
@ManyToMany
@JoinTable(name="CABIN_RESERVATION",
joinColumns={@JoinColumn(name="RESERVATION_ID")},
inverseJoinColumns={@JoinColumn(name="CABIN_ID")})
public Set<Cabin> getCabins( ) { return cabins; }
...
}
24
Jednokierunkowa relacja N:N
<entity-mappings>
<entity class="com.titan.domain.Reservation" access="PROPERTY">
<attributes>
<id name="id">
<generated-value/>
</id>
<many-to-many name="cabins"
target-entity="com.titan.domain.Cabin" fetch="LAZY">
<join-table name="CABIN_RESERVATION">
<join-column name="RESERVATION_ID"/>
<inverse-join-column name="CABIN_ID"/>
</join-table>
</many-to-many>
</attributes>
</entity>
</entity-mappings>
25
Relacje reprezentowanie
przez kolekcje
JPA umożliwia stosowanie następujących kolekcji do reprezentowania relacji jedendo-wielu i wiele-do-wielu: java.util.Collection, java.util.Set,
java.util.List i java.util.Map.
...
@ManyToMany
@OrderBy("lastName ASC")
@JoinTable(name="RESERVATION_CUSTOMER"),
joinColumns={@JoinColumn(name="RESERVATION_ID")},
inverseJoinColumns={@JoinColumn(name="CUSTOMER_ID")})
public List<Customer> getCustomers( ) { return customers; }
<many-to-many name="customers"
target-entity="com.titan.domain.Customer" fetch="LAZY">
<order-by>lastName ASC</order-by>
<join-table name="RESERVATION_CUSTOMER">
<join-column name="RESERVATION_ID"/>
<inverse-join-column name="CUSTOMER_ID"/>
</join-table>
</many-to-many>
26
java.util.Map
...
@OneToMany(cascade={CascadeType.ALL})
@JoinColumn(name="CUSTOMER_ID")
@MapKey(name="number")
public Map<String, Phone> getPhoneNumbers( ) {
return phoneNumbers;
}
<one-to-many name="phoneNumbers"
target-entity="com.titan.domain.Phone" fetch="LAZY">
<cascade-all/>
<map-key name="number"/>
<join-column name="CUSTOMER_ID"/>
</one-to-many>
27
Podsumowanie
JEE w ramach odwzorowania relacyjno-obiektowego umożliwia korzystanie
z siedmiu typów relacji. Odwzorowanie jest określone poprzez mechanizm adnotacji
lub konfigurację zapisaną w pliku persistance.xml. Aby modelować relacje
obejmujące wiele obiektów możemy korzystać z czterech podstawowych typów
kolekcji.
28

Podobne dokumenty