Dziedziczenie i język EJB QL

Transkrypt

Dziedziczenie i język EJB QL
Dziedziczenie i język EJB QL
1. Odwzorowanie hierarchii komponentów encyjnych
●
SINGLE_TABLE,
●
TABLE_PER_CLASS,
●
JOINED.
2. Podstawy języka zapytań EJB QL
●
interfejs Query,
●
proste zapytania,
●
relacje i złączenia,
●
operatory IS EMPTY, MEMBER OF,
●
podzapytania
zapytania nazwane.
1
Komponenty encyjne
a dziedziczenie
Specyfikacja Java Persistence Api pozwala opisać dziedziczenie, polimorfizm,
relacje oraz zapytania polimorficzne. JPA dopuszcza trzy sposoby
odwzorowania hierarchii encji:
- pojedyncza tabela dla całej hierarchii klas,
- osobna tabela dla każdej klasy,
- osobna tabela dla każdej podklasy.
2
Komponenty encyjne
a dziedziczenie
public class
private
private
private
Person implements java.io.Serializable{
int id;
String firstName;
String lastName;
...
}
public class
private
private
private
private
...
}
Customer extends Person {
String street;
String city;
String state;
String zip;
public class Employee extends Customer {
private int employeeId;
...
}
3
Pojedyncza tabela
Pojedyncza tabela odwzorowuje wszystkie klasy w ramach danej hierarchii.
create table PERSON_HIERARCHY(
id integer primary key not null,
firstName varchar(255),
lastName varchar(255),
street varchar(255),
city varchar(255),
state varchar(255),
zip varchar(255),
employeeId integer,
DISCRIMINATOR varchar(31) not null
);
4
Pojedyncza tabela
@Entity
@Table(name="PERSON_HIERARCHY")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="DISCRIMINATOR",
discriminatorType=DiscriminatorType.STRING)
@DiscriminatorValue("PERSON")
public class Person implements java.io.Serializable{
...
}
@Entity
@DiscriminatorValue("CUST")
public class Customer extends Person {
...
}
@Entity
// domyślny dyskryminator: Employee – nazwa komponentu
public class Employee extends Customer {
...
}
5
Pojedyncza tabela
<entity-mappings>
<entity class="com.titan.domain.Person">
<inheritance strategy="SINGLE_TABLE"/>
<discriminator-column name="DISCRIMINATOR"
discriminator-type="STRING"/>
<discriminator-value>PERSON</discriminator-value>
<attributes>
<id>
<generated-value/>
</id>
</attributes>
</entity>
<entity class="com.titan.domain.Customer">
<discriminator-value>CUST</discriminator-value>
</entity>
<entity class="com.titan.domain.Employee"/>
</entity-mappings>
6
Pojedyncza tabela
Zalety:
- prosta koncepcyjnie,
- duża wydajność.
Wady:
- dużo pól o wartości NULL,
- atrybuty klas potomnych muszą przyjmować wartości NULL,
- brak postaci normalnej.
7
Osobne tabele dla klas
create table Person (
id integer primary key not null,
firstName varchar(255),
lastName varchar(255),
);
create table Customer (
id integer primary key not null,
firstName varchar(255),
lastName varchar(255),
create table Employee (
street varchar(255),
id integer primary key not null,
city varchar(255),
firstName varchar(255),
state varchar(255),
lastName varchar(255),
zip varchar(255),
street varchar(255),
);
city varchar(255),
state varchar(255),
zip varchar(255),
employeeId integer,
);
8
Osobne tabele dla klas
@Entity
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public class Person implements java.io.Serializable{
...
}
@Entity
public class Customer extends Person {
...
}
@Entity
public class Employee extends Customer {
...
}
9
Osobne tabele dla klas
<entity-mappings>
<entity class="com.titan.domain.Person">
<inheritance strategy="TABLE_PER_CLASS"/>
<attributes>
<id>
<generated-value/>
</id>
</attributes>
</entity>
<entity class="com.titan.domain.Customer"/>
<entity class="com.titan.domain.Employee"/>
</entity-mappings>
10
Osobne tabele dla klas
Zalety:
- możliwość określenia dodatkowych warunków dla atrybutów (np. wartość
domyślna),
- prostsze odwzorowanie.
Wady:
- brak postaci normalnej,
- redundancja,
- niska wydajność: dużo dodatkowych operacji w celu odwzorowania relacji itp.
Zwykle nie zaleca się stosowania tej strategii odwzorowania hierarchii klas.
11
Osobne tabele dla podklas
create table Person (
id integer primary key not null,
firstName varchar(255),
lastName varchar(255),
);
create table Customer (
id integer primary key not null,
street varchar(255),
city varchar(255),
state varchar(255),
zip varchar(255),
);
create table Employee (
EMP_PK integer primary key not null,
employeeId integer
);
12
Osobne tabele dla podklas
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public class Person {
...
}
@Entity
public class Customer extends Person {
...
}
@Entity
@PrimaryKeyJoinColumn(name="EMP_PK")
public class Employee extends Customer {
...
}
13
Osobne tabele dla podklas
<entity-mappings>
<entity class="com.titan.domain.Person">
<inheritance strategy="JOINED"/>
<attributes>
<id>
<generated-value/>
</id>
</attributes>
</entity>
<entity class="com.titan.domain.Customer"/>
<entity class="com.titan.domain.Employee">
<primary-key-join-column name="EMP_PK"/>
</entity>
</entity-mappings>
14
Osobne tabele dla podklas
Zalety:
- możliwość określenia dodatkowych warunków dla atrybutów (np. wartość
domyślna),
- prostsze odwzorowanie,
- zwykle większa wydajność niż TABLE_FOR_CLASS,
- model normalizowalny.
Wady:
- mniejsza wydajność niż SINGLE_TABLE.
15
Nieencyjne klasy bazowe
@MappedSuperclass
public class Person {
@Id @GeneratedValue
public int getId( ) { return id; }
...
}
@Entity
@Table(name="CUSTOMER")
@Inheritance(strategy=InheritanceType.JOINED)
// atrybut lastName z nadklasy będzie odwzorowany w tabeli CUSTOMER
// w pole SURNAME (domyślnie byłby w polu lastName)
@AttributeOverride(name="lastName", column=@Column(name="SURNAME"))
public class Customer extends Person {
...
}
@Entity
@Table(name="EMPLOYEE")
@PrimaryKeyJoinColumn(name="EMP_PK")
public class Employee extends Customer {
...
}
16
Nieencyjne klasy bazowe
<entity-mappings>
<mapped-superclass class="com.titan.domain.Person">
<attributes>
<id>
<generated-value/>
</id>
</attributes>
</mapped-superclass>
<entity class="com.titan.domain.Customer">
<inheritance strategy="JOINED"/>
<attribute-override name="lastName">
<column name="SURNAME"/>
</attribute-override>
</entity>
<entity class="com.titan.domain.Employee">
<primary-key-join-column name="EMP_PK"/>
</entity>
</entity-mappings>
17
Elementy EJB QL
EJB QL jest deklaratywnym językiem zapytań służącym do przetwarzania
obiektów Javy. Zapytania zapisane w języku EJB QL są tłumaczone przez
kontener komponentów na jedno lub kilka zapytań SQL, które są kierowane
do bazy danych poprzez interfejs JDBC. Język EJB QL nie zawsze jest
wystarczającym narzędziem jednak jego stosowanie gwarantuje przenośność
18
Elementy EJB QL
try {
Query query = entityManager.creatQuery(
"from Customer c where c.firstName='Bill' and
c.lastName='Burke'");
Customer cust = (Customer)query.getSingleResult( );
} catch (EntityNotFoundException notFound) {
} catch (NonUniqueResultException nonUnique){
}
Wykonywanie zapytań odbywa się za pomocą interfejsu Query, który nieco
przypomina, stosowany w JDBC interfejs java.sql.PreparedStatement.
Odbieranie wyników zapytania jest możliwe poprzez dwie metody:
public List getResultList( );
public Object getSingleResult( );
19
Elementy EJB QL
Parametry pełnią identyczną rolę jak w przypadku PreparedStatement mogą
być nazywane (zalecane):
Query query = entityManager.createQuery(
"from Customer c where c.firstName=:first and c.lastName=:last");
query.setParameter("first", first);
query.setParameter("last", last);
java.util.List list = query.getResultList( );
oraz numerowane:
Query query = entityManager.createQuery(
"from Customer c where c.firstName=?1 and c.lastName=?2");
query.setParameter(1, first);
query.setParameter(2, last);
query.getResultList( );
20
Proste zapytania
SELECT OBJECT( c ) FROM Customer AS c
SELECT c FROM Customer AS c
SELECT c FROM Customer c
Jeśli klauzula SELECT obejmuje więcej niż jedną kolumnę pojedynczym
wynikiem jest tablica Object[].
Query query = manager.createQuery(
"SELECT c.firstName, c.lastName FROM Customer AS
c");
List results = query.getResultList( );
Iterator it = results.iterator( );
while (it.hasNext( )) {
Object[] result = (Object[])it.next( );
String first = (String)result[0];
String last = (String)result[1];
}
21
Proste zapytania
public class Name {
private String first;
private String last;
public Name(String first, String last) {
this.first = first;
this.last = last;
}
...
}
SELECT new Name(c.firstName, c.lastName) FROM Customer c
W wyniku zapytania zostanie zwrócony obiekt Name lub ich lista.
22
Zapytania a relacje
Customer
1:1
CreditCard
N:1
CreditCompany
1:1
Address
SELECT c.creditCard.creditCompany.address.city FROM Customer AS c
@Entity
public class Address {
...
private ZipCode zip;
}
public class ZipCode implements java.io.Serializable {
public int mainCode, codeSuffix;
...
}
SELECT c.address.zip.mainCode FROM Customer AS c // źle
@Entity
public class Address {
...
@Embedded private ZipCode zip;
}
SELECT c.address.zip.mainCode FROM Customer AS c
// dobrze
23
Zapytania a relacje (JOIN)
Customer
N:N
Reservation
N:1
Cruise
N:1
Ship
N:1
SELECT c.reservations.cruise FROM Customer AS c
// źle EJB QL
customer.getReservations().getCruise();
// źle Java
SELECT r.cruise FROM Customer AS c, IN( c.reservations ) r
SELECT r.cruise FROM Customer c INNER JOIN c.reservations r
SELECT r.cruise FROM Customer c JOIN c.reservations r
SELECT cb.ship FROM Customer c JOIN c.reservations r JOIN
r.cabins cb
24
Zapytania a relacje (LEFT
JOIN)
Customer
1:N
Phone
SELECT c.firstName, c.lastName, p.number FROM Customer c
LEFT JOIN c.phones p
Adam Kot (12)654 32 11
Julia Zielińska (17)908 23 44
Julia Zielińska 0 690 579 870
Aneta Czarnecka null
SELECT c.firstName, c.lastName, p.number FROM Customer c
LEFT OUTER JOIN c.phones p
SELECT c.firstName, c.lastName, p.number FROM Customer c
LEFT JOIN FETCH c.phones p
25
Klauzula WHERE, operator
IS EMPTY
Podobnie jak w języku SQL, klauzula WHERE obsługuje porównania, operacje
arytmetyczne, logiczne oraz operatory IN, BETWEEN, LIKE, IS NULL.
Inne operatory: IS EMPTY
// rejsy bez rezerwacji:
SELECT crs FROM Cruise AS crs WHERE crs.reservations IS EMPTY
// rejsy z co najmniej jedną rezerwacją:
SELECT crs FROM Cruise AS crs WHERE crs.reservations IS NOT
EMPTY
// niepoprawne – zbiór wynikowy: rozpatrywane są tylko
rezerwacje z niepustymi customers ze względu na wcześniejsze
złączenie.
SELECT r FROM Reservation AS r INNER JOIN r.customers AS c
WHERE r.customers IS NOT EMPTY AND c.address.city = 'Boston'
26
Klauzula WHERE, operator
MEMBER OF
// lista rejsów dla których dany klient dokonał rezerwacji:
SELECT crs FROM Cruise AS crs, IN (crs.reservations) AS res,
Customer AS cust WHERE cust = :myCustomer AND cust MEMBER OF
res.customers
// lista rejsów dla których dany klient nie dokonał rezerwacji:
SELECT crs FROM Cruise AS crs, IN (crs.reservations) AS res,
Customer AS cust WHERE cust = :myCustomer AND cust NOT MEMBER OF
res.customers
Jeśli sprawdzamy, czy encja jest składową kolekcji pustej otrzymamy wartość
false. EJB QL umożliwia stosowanie podstawowych funkcji i operacji
agregujących. Można także używać klauzul DISTINCT, ORDER BY, GROUP
BY oraz HAVING.
27
Podzapytania
// liczba rezerwacji o wartości większej niż wartość średnia
SELECT COUNT(res) FROM Reservation res
WHERE res.amountPaid > (SELECT avg(r.amountPaid) FROM
Reservation r)
// rejsy z zapłaconymi wszystkimi rezerwacjami
SELECT cr FROM Cruise cr
WHERE 0 < ALL (SELECT res.amountPaid FROM cr.reservations res)
// rejsy z co najmniej jedną nie zapłaconą rezerwacją ANY <->
SOME
SELECT cr FROM Cruise cr
WHERE 0 = ANY (SELECT res.amountPaid from cr.reservations res);
28
Zapytania nazwane
@NamedQueries({
@NamedQuery(name="findFullyPaidCruises", query= "FROM Cruise cr
WHERE
0 < ALL ( SELECT res.amountPaid from cr.reservations res)")
})
@Entity
public class Cruise {...}
...
// wywołanie zapytania
Query query = em.createNamedQuery("findFullyPaidCruises");
<entity-mappings>
<named-query name="findFullyPaidCruises">
<query>
FROM Cruise cr WHERE
0 &lt; ALL ( SELECT res.amountPaid from cr.reservations res)
</query>
</named-query>
</entity-mappings>
29
Inne operacje
Interfejs Query umożliwia także wykonywanie zbiorowej aktualizacji
i usuwania rekordów (UPDATE, DELETE) za pośrednictwem metody
executeUpdate(). Istnieje także możliwość bezpośredniego wywołania
zapytań SQL oraz zapytań nazwanych SQL.
30
Podsumowanie
Specyfikacja JPA umożliwia elastyczne odwzorowanie obiektów Javy do
relacyjnego modelu danych. Do podstawowych cech takiego odwzorowania
dodano możliwość dziedziczenia komponentów encyjnych oraz określono
funkcjonalny, zapewniający przenośność obiektowy język zapytań.
31

Podobne dokumenty