7. Programación en datos estructurados
7.1 Capas de toda aplicación
Presentation
- Interfaces de usuario
- Interfaces con otras aplicaciones
Business
- Toda la lógica que involucra toda operación en nuestra
aplicación.
- Componentes reutilizables que pueden servir para distintas aplicaciones.
Integration
- Bases de datos
- Legacy Systems
7.2 Programación con patrones
7.2.1 Transfer Object
Problema
Se desean tranferir múltiples elementos de datos a través de
capas.
Características
- Se desean accesar datos a traves de capas para recuperar o almacenar información.
- Reducir el número de operaciones/peticiones a través de la
red
- Reducir el tráfico de red
Solución
Usar un Transfer Object para llevar múltiples elementos a través
de una capa.
Class diagram
Sequence diagram
Estrategias
- Los objetos son actualizables
- Se pueden manejar varios objetos a la vez
Efectos
- Disminuye el tráfico de red
- Simplifica el uso de interfaces "remote"
- Se transfieren más datos en menos llamadas remotas
- Reduce la duplicación de código
- Aumenta la complejidad porque involucra el manejo de sincronización
1:Example 8.1 CustomerTO.java: Transfer Object Used by CustomerDAO and Its Clients
2:package com.corej2eepatterns.to;
3:
4:public class CustomerTO implements java.io.Serializable {
5: private String id;
6: private String name;
7: private String address;
8: . . .
9:
10: public String getId(){ return id; }
11: public void setId(String id){ this.id = id; }
12: public String getName(){ return name; }
13: public void setName(String name){ this.name = name; }
14: public String getAddress(){ return address; }
15: public void setAddress(String address){
16: this.address = address;
17: }
18: // other getters and setters
19: . . .
20:}
|
7.2.2 Data Access Object
Problema
Se desea encapsular acceso a datos y manipulación de los mismos en capas
separadas.
Características
- Se quiere tener mecanismos para el manejo de acceso y manipulación
de datos pero en un almacenamiento persistente.
- Aislar el almacenamiento persistente del resto de la aplicación.
- Interfaz uniforme para distintos tipos de repositorios RDBMS, LDAP, OODB,
XML repositories, flat files, etc.
- Encapsular información propietaria para facilitar mantenimiento
y portabilidad.
Solución
Emplear un Data Access Object DAO para abstraer y encapsular todos los accesos
al almacenamiento persistente. El Data Access Object maneja las conexiones para
guardar y recuperar datos.
Class diagram
Sequence diagram
Estrategias
- Se puede crear un procedimiento a la medida si se desea
- Se pueden crear "factories" de DAO para simplificar por ejemplo
las conexiones
- Interacción con los TO
Efectos
- Centraliza el control de manejadores débilmente acoplados
- Simplifica la transparencia
- Provee una vision object-oriented y encapsula el concepto de esquemas de
bases de datos
- Reduce la complejidad de códigos en clientes
- Organización en una capa totalmente separada
- Requiere de Jerarquías
- Introduce complejidad en el manejo de RowSet Wrapper List
1:Example 8.2 CustomerDAO.java: Data Access Object
2:package com.corej2eepatterns.dao;
3:
4:// imports
5:
6:public class CustomerDAO {
7: protected static final String FIELDS_INSERT =
8: "customer_name, customer_address, " +
9: "customer_contact, customer_phone, customer_email";
10:
11: protected static final String FIELDS_RETURN =
12: "customer_id, " + FIELDS_INSERT;
13:
14: protected static String INSERT_SQL =
15: "insert into customer ( " + FIELDS_INSERT +
16: " ) " + "values ( ?, ?, ?, ?, ?)";
17:
18: protected static String SELECT_SQL = "select " +
19: FIELDS_RETURN +
20: " from customer where customer_id = ? ";
21:
22: protected static String UPDATE_SQL =
23: "update customer set customer_name = ?, " +
24: "customer_address = ?, customer_contact = ?, " +
25: "customer_phone = ?, customer_email = ? " +
26: "where customer_id = ? ";
27:
28: protected static String DELETE_SQL =
29: "delete from Customer where customer_id = ? ";
30:
31: // the data source used to connect to the back-end database
32: private DataSource datasource;
33:
34: public CustomerDAO() throws DAOException {
35: try {
36: // Shown here for clarity only. Typically, looking
37: // up a data source is done by a Service Locator
38: // and the DAO just uses the Service Locator to
39: // obtain a data source.
40: InitialContext initialContext =
41: new InitialContext();
42: datasource = (DataSource) initialContext.lookup(
43: OracleDAOFactory.DATASOURCE_DB_NAME);
44: } catch (NamingException e) {
45: throw new DAOException (
46: "Cannot locate data source at " +
47: DAOFactory.DATASOURCE_DB_NAME, e);
48: }
49: }
50:
51: public String create(CustomerTO cust) throws DAOException {
52: // initialize variables
53: Connection con = getConnection();
54: String customerId = null;
55:
56: PreparedStatement prepStmt = null;
57: try {
58: // create and setup statement
59: prepStmt = con.prepareStatement(INSERT_SQL);
60: int i = 1;
61: prepStmt.setString(i++, cust.getName());
62: prepStmt.setString(i++, cust.getAddress());
63: . . .
64:
65: // execute the statement
66: prepStmt.executeUpdate();
67:
68: // obtain the newly created customer id value
69: . . .
70:
71: } catch (Exception e) {
72: // handle exception
73: } finally {
74: // close connections
75: }
76:
77: // return the newly created customer id value
78: return customerId;
79: }
80:
81: public CustomerTO find(String customerId)
82: throws DAOException {
83: // initialize variables
84: CustomerTO cust = null;
85: Connection con = getConnection();
86: PreparedStatement prepStmt = null;
87: ResultSet rs = null;
88:
89: try {
90: // setup statement and retrieve results
91: prepStmt = con.prepareStatement(SELECT_SQL);
92: prepStmt.setString(1, customerId);
93: rs = prepStmt.executeQuery();
94: if (rs.next()) {
95: //create the transfer object using data from rs
96: cust = new CustomerTO();
97: cust.setId(rs.getString(1));
98: cust.setName(rs.getString(2));
99: . . .
100: }
101: } catch (Exception e) {
102: // handle exception
103: } finally {
104: // close connections
105: }
106: return cust;
107: }
108:
109: public void update(CustomerTO cust) throws DAOException {
110: Connection con = null;
111: PreparedStatement prepStmt = null;
112: try {
113: // prepare statement
114: con = getConnection();
115:
116: prepStmt = con.prepareStatement(UPDATE_SQL);
117: int i = 1;
118:
119: // add fields first
120: prepStmt.setString(i++, cust.getName());
121: prepStmt.setString(i++, cust.getAddress());
122: . . .
123:
124: // now add where parameters
125: prepStmt.setString(i++, cust.getId());
126: int rowCount = prepStmt.executeUpdate();
127: prepStmt.close();
128: if (rowCount == 0) {
129: throw new DAOException(
130: "Update Error:Customer Id:" + cust.getId());
131: }
132: } catch (Exception e) {
133: // handle exception
134: } finally {
135: // close connections
136: }
137: }
138:
139: public void delete(String customerId) throws Exception {
140: // setup variables
141: Connection con = getConnection();
142: PreparedStatement prepStmt = null;
143:
144: try {
145: // execute database update
146: prepStmt = con.prepareStatement(DELETE_SQL);
147: prepStmt.setString(1, customerId);
148: prepStmt.executeUpdate();
149: } catch (Exception e) {
150: // handle exception
151: } finally {
152: // close connections
153: }
154: }
155:
156: // other methods for finders, etc.
157: . . .
158:}
|
7.3 Java Persistence API (JPA)
7.3.1 Arquitectura
Es parte de la suite JavaEE
http://java.sun.com/javaee/5/docs/api/
7.3.2 Annotations
7.3.3 Queries en JPA
API
package javax.persistence;
public interface Query {
public List getResultList( );
public Object getSingleResult( );
public int executeUpdate( );
public Query setMaxResults(int maxResult);
public Query setFirstResult(int startPosition);
public Query setHint(String hintName, Object value);
public Query setParameter(String name, Object value);
public Query setParameter(String name, Date value, TemporalType temporalType);
public Query setParameter(String name, Calendar value, TemporalType temporalType);
public Query setParameter(int position, Object value);
public Query setParameter(int position, Date value, TemporalType temporalType);
public Query setParameter(int position, Calendar value, TemporalType temporalType);
public Query setFlushMode(FlushModeType flushMode);
}
Queries are created using these EntityManager methods:
package javax.persistence;
public interface EntityManager {
public Query createQuery(String ejbqlString);
public Query createNamedQuery(String name);
public Query createNativeQuery(String sqlString);
public Query createNativeQuery(String sqlString, Class resultClass);
public Query createNativeQuery(String sqlString, String resultSetMapping);
}
|
EJBQL Queries at runtime
try {
Query query = entityManager.createQuery(
"from Customer c where c.firstName='Bill' and c.lastName='Burke'");
Customer cust = (Customer)query.getSingleResult( );
} catch (EntityNotFoundException notFound) {
} catch (NonUniqueResultException nonUnique) {
} |
EJBQL Named Queries
@NamedQueries({
@NamedQuery
(name="getAverageReservation",
query=
"SELECT AVG( r.amountPaid)
FROM Cruise As c, JOIN c.reservations r
WHERE c = :cruise"),
@NamedQuery(name="findFullyPaidCruises",
query=
"FROM Cruise cr
WHERE 0 < ALL (
SELECT res.amountPaid from cr.reservations res
)")
})
@Entity
public class Cruise {...}
Query query = em.createNamedQuery("getAverageReservation");
Query.setParameter("cruise", cruise);
|
Parameters
public List findByName(String first, String last) {
Query query = entityManager.createQuery(
"from Customer c where c.firstName=:first and c.lastName=:last");
query.setParameter("first", first);
query.setParameter("last", last);
return query.getResultList( );
}
public List findByName(String first, String last) {
Query query = entityManager.createQuery(
"from Customer c where c.firstName=?1 and c.lastName=?2");
query.setParameter(1, first);
query.setParameter(2, last);
return query.getResultList( );
}
|
Native (SQL) Queries
Query query = manager.createNativeQuery(
"SELECT p.phone_PK, p.phone_number, p.type
FROM PHONE AS p", Phone.class
);
|
7.3.4 EJB QL Examples
Select
SELECT OBJECT(c) FROM Customer AS c
o
SELECT c FROM Customer c
SELECT c.creditCard.creditCompany.address.city FROM Customer AS c |
SELECT c.firstName, c.lastName FROM Customer AS c
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];
}
|
The IN Operator and INNER JOIN
All the reservations of all the customers
SELECT r FROM Customer AS c, IN( c.reservations ) r
o
SELECT r.cruise FROM Customer c INNER JOIN c.reservations r |
All ships for which customers have reservations
SELECT cbn.ship
FROM Customer AS c, IN ( c.reservations ) r,
IN( r.cabins ) cbn |
Fetch Joins
@OneToMany(fetch=FetchType.LAZY)
public Collection getPhones( ) { return phones; }
...
1 Query query = manager.createQuery("SELECT c FROM Customer c");
2 List results = query.getResultList( );
3 Iterator it = results.iterator( );
4 while (it.hasNext( )) {
5 Customer c = (Customer)it.next( );
6 System.out.print(c.getFirstName( ) + " " + c.getLastName( ));
7 for (Phone p : c.getPhoneNumbers( )) {
8 System.out.print(p.getNumber( ) + " ");
9 }
10 System.out.println("");
11 }
|
Distinct
SELECT DISTINCT cust FROM Reservation AS res, IN (res.customers) cust |
Where
SELECT c
FROM Customer AS c
WHERE c.creditCard.creditCompany.name = 'Capital One'
SELECT s
FROM Ship AS s
WHERE s.tonnage >= 80000.00 AND s.tonnage <= 130000.00
SELECT c
FROM Customer AS c
WHERE c.address.state IN ('FL', 'TX', 'MI', 'WI', 'MN')
SELECT c
FROM Customer AS c
WHERE c.address IS NULL
SELECT OBJECT( c ) FROM Customer AS c
WHERE c.lastName LIKE '%-%'
|
Where Operators
...BETWEEN 8 AND 16
....Address.state IN ('FL','TX',?1)
NOT IN (similar al IN)
...IS NULL ....IS NOT NULL
...crs.reservations IS NOT EMPTY
..phone.number LIKE '222%'
Functional Expressions
CONCAT(String1, String2)
LENGTH(String)
LOCATE(String1, String2 [,start])
SUBSTRING(String1, start, length)
ABS(number)
SQRT(double)
MOD(int,int)
Aggregate functions (select)
COUNT(identifier or path expression)
MAX(path expresssion), MIN (path expression)
AVG(numeric), SUM(numeric)
|