View
112
Download
0
Category
Preview:
Citation preview
Object Relational Mapping - ORM
Tutor: Ing. Juan E. Talavera Horn
2010
ORM - Concepto
Conversión automática de objetos de aplicación a filas en tablas relacionales y viceversa
ORM - Objetivos
Reducir la codificación de código SQL trivial para mantenimiento de objetos en la base de datos
Facilitar la navegación entre datos y sus relaciones en término de objetos de aplicación
ORM - Frameworks
Hibernate - Java TopLink - Java Enterprise Java Beans - Java Zend – php NHibernate – .NET Rails – Ruby
Hibernate - Introducción
package events;import java.util.Date;public class Event {
private Long id; private String title; private Date date;
public Event() {}
public Long getId() {return id;
} private void setId(Long id) {
this.id = id; }
public Date getDate() {return date;
}
public void setDate(Date date) {this.date = date;
} public String getTitle() {
return title; } public void setTitle(String title) {
this.title = title; }}
POJO: Plain Old Java Object
Configuración de mapeo
<hibernate-mapping> <class name="events.Event" table="EVENTS">
<id name="id" column="EVENT_ID"> <generator class="native"/></id>
<property name="date" type="timestamp" column="EVENT_DATE"/>
<property name="title"/>
</class></hibernate-mapping>
Crear y almacenar nuevo objeto
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
//Iniciar transacciónsession.beginTransaction();
Event theEvent = new Event();
theEvent.setTitle(title);theEvent.setDate(theDate);
session.save(theEvent);
//Confirmar transacciónsession.getTransaction().commit();
Obtener lista de objetos desde BD
//Método en clase EventManagerprivate List listEvents() { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); List result = session.createQuery("from Event").list(); return result;}
//Desde algún cliente de EventManagerList events = mgr.listEvents();for (int i = 0; i < events.size(); i++) { Event theEvent = (Event) events.get(i); System.out.println("Event: " + theEvent.getTitle() + " Time: " + theEvent.getDate());}
Mapear asociacionespackage events;public class Person {
private Long id;private int age;private String firstname;private String lastname;private Set events = new HashSet();
public Person() {}
// getters y setters para todos los atributos}
<hibernate-mapping> <class name="events.Person" table="PERSON">
<id name="id" column="PERSON_ID"> <generator class="native"/></id><property name="age"/><property name="firstname"/><property name="lastname"/>
<set name="events" table="PERSON_EVENT"> <key column="PERSON_ID"/> <many-to-many column="EVENT_ID"
class="events.Event"/></set>
</class></hibernate-mapping>
Mapear asociaciones
Accediendo a las relacionesprivate void addPersonToEvent(Long personId, Long eventId) {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
Person aPerson = (Person) session.load(Person.class, personId); Event anEvent = (Event) session.load(Event.class, eventId);
aPerson.getEvents().add(anEvent);
session.getTransaction().commit();}
Annotations
Sustituir configuración XML por annotations
Annotations estándares de EJB 3.0 Annotations específicos de Hibernate POJO + Annotations EJB 3.0 =
Entity Java Beans Hibernate cumple con especificación JPA JPA puede ejecutarse fuera de contenedor
EJB, ejemplo Apache Tomcat
POJO + Annotations
@Entitypublic class Flight implements Serializable {
Long id;
@Idpublic Long getId() { return id; }
public void setId(Long id) { this.id = id; }}
Anotaciones sobre los getters o declaración de los atributos
@Table(…)
@Entity@Table(name="tbl_sky")public class Sky implements Serializable {
...}
Optimistic Locking
@Entitypublic class Flight implements Serializable {
private Integer version;...
@Version@Column(name="OPTLOCK")public Integer getVersion() {
return version; }
}
EJB 3 requiere soporte para bloqueo optimista, pero no así parabloqueo pesimista.
Mapeo de propiedades simplespublic transient int counter; //transient property
private String firstname; //persistent property
@TransientString getLengthInMeter() { ... } //transient property
String getName() {... } // persistent property
@Basicint getLength() { ... } // persistent property
@Temporal(TemporalType.TIME)java.util.Date getDepartureTime() { ... } // persistent property
@Column
@Entitypublic class Flight implements Serializable { ...
@Column(name = "flight_name", nullable = false, length=50) public String getName() { ... }
@Id
@Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_STORE")@SequenceGenerator(name=“SEQ_STORE",sequenceName=“SQ_IDSTORE")public Integer getId() { ... }
•AUTO: Uno de los siguientes dependiendo de la BD•TABLE: Valor almacenado en una tabla•IDENTITY: Auto incrementado por la BD (si soporta)•SEQUENCE: A partir de secuencia
Claves primarias compuestas
Anotar la propiedad con @Id, y la clase de la clave con @Embeddable
Anotar la propiedad con @EmbeddedId
Anotar la clase con @IdClass y anotar cada propiedad que conforma la clase con @Id
Anotar la propiedad con @Id, y la clase de la clave con @Embeddable
@Entitypublic class DetalleFactura {
@Id DetalleFacturaKey id;
...}
@Embeddablepublic class DetalleFacturaKey { private Integer idCabeceraFactura; private Integer nroDetalle;}
Anotar la propiedad con @EmbeddedId
@Entitypublic class DetalleFactura {
@EmbeddedId DetalleFacturaKey id;
...}
public class DetalleFacturaKey { private Integer idCabeceraFactura; private Integer nroDetalle;}
Anotar la clase con @IdClass y anotar cada propiedad que conforma la clase con @Id
@Entity@IdClass(DetalleFacturaKey.class)public class DetalleFactura {
@Id private Integer idCabeceraFactura;
@Id Integer nroDetalle; ...}
@Embeddablepublic class DetalleFacturaKey { private Integer idCabeceraFactura; private Integer nroDetalle;}
Asociación 1 a 1
Las entidades asociadas tienen las mismas claves primarias
Una de las entidades tiene un foreign key a la otra
Existe una tabla intermedia que mantiene la relación entre las 2 entidades
Las entidades asociadas tienen las mismas claves primarias
@Entitypublic class Body { @Id public Long getId() { return id; }
@OneToOne(cascade = CascadeType.ALL) @PrimaryKeyJoinColumn public Heart getHeart() {
return heart; } ...}
@Entitypublic class Heart { @Id public Long getId() { ...}}
Una de las entidades tiene un foreign key a la otra
@Entitypublic class Customer {
@OneToOne(cascade = CascadeType.ALL) @JoinColumn(name="passport_fk") public Passport getPassport() {}
...}
@Entitypublic class Passport {
@OneToOne(mappedBy = "passport") public Customer getOwner() {} ...}
En relación bidireccional, owner class es la encargada del mantenimiento de la relación
Tabla intermedia mantiene la relación entre las 2 entidades
@Entitypublic class Customer implements Serializable {
@OneToOne(cascade = CascadeType.ALL) @JoinTable(name = "CustomerPassports", joinColumns = @JoinColumn(name="customer_fk"), inverseJoinColumns = @JoinColumn(name="passport_fk")) public Passport getPassport() {}...}
@Entitypublic class Passport implements Serializable { @OneToOne(mappedBy = "passport") public Customer getOwner() {}...}
Asociación muchos a uno
@Entity()public class Flight implements Serializable {
@ManyToOne(cascade={CascadeType.PERSIST,CascadeType.MERGE} ) @JoinColumn(name="COMP_ID") public Company getCompany() {
return company; } ...}
Collections
@Entity()public class Company implements Serializable {
public String getName() { …}
@OneToMany(mappedBy=“company") public List<Flight> getFlights() {
return flights; } ...}
Invertir el “owner” de la relación
@Entitypublic class Troop { @OneToMany @JoinColumn(name="troop_fk") public Set<Soldier> getSoldiers() {}
...}
@Entitypublic class Soldier { @ManyToOne @JoinColumn(name="troop_fk", insertable=false, updatable=false) public Troop getTroop() {}
...}
Foreign key compuestos@Entitypublic class Parent implements Serializable { @Id public ParentPk id; public int age;
@OneToMany(cascade=CascadeType.ALL) @JoinColumns ({ @JoinColumn(name="parentCivility", referencedColumnName = "isMale"), @JoinColumn(name="parentLastName", referencedColumnName = "lastName"), @JoinColumn(name="parentFirstName", referencedColumnName = "firstName") }) public Set<Child> children; ...}
Named Query<entity-mappings> <named-query name="plane.getAll">
<query>select p from Plane p</query> </named-query> ...</entity-mappings>
@Entity@NamedQuery(name="night.moreRecentThan",
query="select n from Night n where n.date >= :date")public class Night {...}
public class MyDao { doStuff() {
Query q = s.getNamedQuery("night.moreRecentThan");q.setDate( "date", aMonthAgo );List results = q.list();...
} ...}
Criteria Query
List cats = sess.createCriteria(Cat.class).add( Restrictions.like("name", "Fritz%") ).add( Restrictions.between("weight", minWeight, maxWeight) ).list();
List cats = sess.createCriteria(Cat.class).add( Restrictions.like("name", "Fritz%") ).add( Restrictions.or(
Restrictions.eq( "age", new Integer(0) ),Restrictions.isNull("age")
) ).list();
Conceptos de la plataforma
Session Factory Session Persistent objects Transient and detached objects Transaction Connection Provider Transaction Factory First Level Cache Second Level Cache
Recommended