[hibernate-commits] Hibernate SVN: r14075 - in core/trunk/documentation/manual/es-ES/src/main: docbook and 2 other directories.
hibernate-commits at lists.jboss.org
hibernate-commits at lists.jboss.org
Tue Oct 9 14:45:36 EDT 2007
Author: steve.ebersole at jboss.com
Date: 2007-10-09 14:45:36 -0400 (Tue, 09 Oct 2007)
New Revision: 14075
Added:
core/trunk/documentation/manual/es-ES/src/main/docbook/Hibernate_Reference.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/
core/trunk/documentation/manual/es-ES/src/main/docbook/content/architecture.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/association_mapping.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/basic_mapping.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/batch.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/best_practices.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/collection_mapping.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/component_mapping.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/configuration.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/events.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/example_mappings.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/example_parentchild.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/example_weblog.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/filters.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/inheritance_mapping.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/performance.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/persistent_classes.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/preface.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/query_criteria.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/query_hql.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/query_sql.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/quickstart.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/session_api.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/toolset_guide.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/transactions.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/tutorial.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/xml.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/images/
core/trunk/documentation/manual/es-ES/src/main/docbook/images/AuthorWork.png
core/trunk/documentation/manual/es-ES/src/main/docbook/images/AuthorWork.zargo
core/trunk/documentation/manual/es-ES/src/main/docbook/images/CustomerOrderProduct.png
core/trunk/documentation/manual/es-ES/src/main/docbook/images/CustomerOrderProduct.zargo
core/trunk/documentation/manual/es-ES/src/main/docbook/images/EmployerEmployee.png
core/trunk/documentation/manual/es-ES/src/main/docbook/images/EmployerEmployee.zargo
core/trunk/documentation/manual/es-ES/src/main/docbook/images/full_cream.png
core/trunk/documentation/manual/es-ES/src/main/docbook/images/full_cream.svg
core/trunk/documentation/manual/es-ES/src/main/docbook/images/hibernate_logo_a.png
core/trunk/documentation/manual/es-ES/src/main/docbook/images/lite.png
core/trunk/documentation/manual/es-ES/src/main/docbook/images/lite.svg
core/trunk/documentation/manual/es-ES/src/main/docbook/images/overview.png
core/trunk/documentation/manual/es-ES/src/main/docbook/images/overview.svg
core/trunk/documentation/manual/es-ES/src/main/docbook/legal_notice.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/legal_notice2.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/translators.xml
Removed:
core/trunk/documentation/manual/es-ES/src/main/docbook/master.xml
core/trunk/documentation/manual/es-ES/src/main/resources/
Log:
new docbook layout (prep for translations migration to PO)
Added: core/trunk/documentation/manual/es-ES/src/main/docbook/Hibernate_Reference.xml
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/Hibernate_Reference.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/Hibernate_Reference.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,88 @@
+<?xml version='1.0' encoding="iso-8859-1"?>
+<!--
+ ~ Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
+ ~
+ ~ This copyrighted material is made available to anyone wishing to use, modify,
+ ~ copy, or redistribute it subject to the terms and conditions of the GNU
+ ~ Lesser General Public License, v. 2.1. This program is distributed in the
+ ~ hope that it will be useful, but WITHOUT A WARRANTY; without even the implied
+ ~ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details. You should have received a
+ ~ copy of the GNU Lesser General Public License, v.2.1 along with this
+ ~ distribution; if not, write to the Free Software Foundation, Inc.,
+ ~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ~
+ ~ Red Hat Author(s): Steve Ebersole
+ -->
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+ <!ENTITY versionNumber "3.3.0.alpha1">
+ <!ENTITY copyrightYear "2004">
+ <!ENTITY copyrightHolder "Red Hat Middleware, LLC.">
+]>
+
+<book>
+
+ <bookinfo>
+ <title>HIBERNATE - Persistencia Relacional para Java Idiomático</title>
+ <subtitle>Documentación de Referencia de Hibernate</subtitle>
+ <releaseinfo>&versionNumber;</releaseinfo>
+ <productnumber>&versionNumber;</productnumber>
+ <issuenum>1</issuenum>
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="images/hibernate_logo_a.png" align="center" />
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="images/hibernate_logo_a.png" depth="3cm" />
+ </imageobject>
+ </mediaobject>
+ <copyright>
+ <year>©rightYear;</year>
+ <holder>©rightHolder;</holder>
+ </copyright>
+ <xi:include href="translators.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include href="legal_notice.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include href="legal_notice2.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ </bookinfo>
+
+ <toc/>
+
+ <xi:include href="content/preface.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+ <xi:include href="content/tutorial.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+ <xi:include href="content/architecture.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+ <xi:include href="content/configuration.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+ <xi:include href="content/persistent_classes.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+ <xi:include href="content/basic_mapping.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include href="content/collection_mapping.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include href="content/association_mapping.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include href="content/component_mapping.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include href="content/inheritance_mapping.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+ <xi:include href="content/session_api.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include href="content/transactions.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include href="content/events.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include href="content/batch.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+ <xi:include href="content/query_hql.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include href="content/query_criteria.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include href="content/query_sql.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include href="content/filters.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include href="content/xml.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+ <xi:include href="content/performance.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+ <xi:include href="content/toolset_guide.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+ <xi:include href="content/example_parentchild.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include href="content/example_weblog.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+ <xi:include href="content/example_mappings.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+ <xi:include href="content/best_practices.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+
+</book>
+
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/content/architecture.xml (from rev 12794, core/trunk/documentation/manual/es-ES/src/main/docbook/modules/architecture.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/architecture.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/architecture.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,279 @@
+<chapter id="architecture">
+
+ <title>Arquitectura</title>
+
+ <sect1 id="architecture-overview" revision="1">
+ <title>Visión General</title>
+
+ <para>
+ Una visión a (muy) alto nivel de la arquitectura de Hibernate:
+ </para>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="../images/overview.svg" format="SVG" align="center"/>
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="../images/overview.gif" format="GIF" align="center"/>
+ </imageobject>
+ </mediaobject>
+
+ <para>
+ Este diagrama muestra a Hibernate usando la base de datos y los datos de
+ configuración para proveer servicios de persistencia (y objetos
+ persistentes) a la aplicación.
+ </para>
+
+ <para>
+ Nos gustaría mostrar una vista más detallada de la arquitectura de tiempo
+ de ejecución. Desafortunadamente, Hibernate es flexible y soporta diferentes
+ enfoques. Mostraremos los dos extremos. En la arquitectura "sencilla", es la
+ aplicación la que provee su propias conexiones JDBC y gestiona sus propias
+ transacciones. Este enfoque usa un mínimo subconjunto de la API de Hibernate:
+ </para>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="../images/lite.svg" format="SVG" align="center"/>
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="../images/lite.gif" format="GIF" align="center"/>
+ </imageobject>
+ </mediaobject>
+
+ <para>
+ La arquitectura "full cream" abstrae a la aplicación de las APIs
+ de JDBC/JTA y deja que Hibernate se encargue de los detalles.
+ </para>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="../images/full_cream.svg" format="SVG" align="center"/>
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="../images/full_cream.gif" format="GIF" align="center"/>
+ </imageobject>
+ </mediaobject>
+
+ <para>
+ He aquí algunas definiciones de los objetos en los diagramas:
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term>SessionFactory (<literal>org.hibernate.SessionFactory</literal>)</term>
+ <listitem>
+ <para>
+ Caché threadsafe (inmutable) de mapeos compilados para
+ una sola base de datos. Es una fábrica de <literal>Session</literal>
+ y un cliente de <literal>ConnectionProvider</literal>. Opcionalmente,
+ puede mantener una caché (de segundo nivel) de datos reusables
+ entre transacciones, a un nivel de proceso o de cluster.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Session (<literal>org.hibernate.Session</literal>)</term>
+ <listitem>
+ <para>
+ Objeto mono-hebra, de corta vida que representa una conversación
+ entre la aplicación y el almacenamiento persistente. Envuelve una
+ conexión JDBC. Es una fábrica de <literal>Transaction</literal>.
+ Mantiene una caché requerida (de primer nivel) de objetos persistentes,
+ usada mientras se navega el grafo de objetos o se recuperen objetos por
+ identificador.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Objetos y colecciones persistentes</term>
+ <listitem>
+ <para>
+ Objetos de corta vida, mono-hebra conteniendo estado persistente y
+ funciónalidad de negocio. Estos pueden ser JavaBeans/POJOs
+ (Plain Old Java Objects, o sea, cualquier objeto Java), la única
+ cosa especial en ellos es que estan asociados actualmente con una
+ (y sólo una) <literal>Session</literal>. Tan pronto como la
+ <literal>Session</literal> sea cerrada, serán separados y
+ estarán libres para ser usados en cualquier capa de aplicación.
+ (por ejemplo, directamente como objetos de transferencia de datos hacia
+ y desde la capa de presentación).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Objetos y colecciones transitorios y separados</term>
+ <listitem>
+ <para>
+ Instancias de clases persistentes que no estan acutualmente asociadas
+ con una <literal>Session</literal>. Pueden haber sido instanciadas por
+ la aplicación y (aún) no haber sido hechas persistentes,
+ o pueden haber sido instanciadas por una <literal>Session</literal> cerrada.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Transaction (<literal>org.hibernate.Transaction</literal>)</term>
+ <listitem>
+ <para>
+ (Opcional) Un objeto de corta vida, mono-hebra, usado por la aplicación
+ para especificar unidades atómicas de trabajo. Abstrae a la aplicación
+ de las subyacentes transacciones JDBC, JTA o CORBA. En algunos casos, una
+ <literal>Session</literal> puede extenderse sobre varias <literal>Transaction</literal>s.
+ Sin embargo, la demarcación de la transacción, ya sea usando la API
+ subyacente o <literal>Transaction</literal>, nunca es opcional!
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>ConnectionProvider (<literal>org.hibernate.connection.ConnectionProvider</literal>)</term>
+ <listitem>
+ <para>
+ (Opcional) Una fábrica (y pool) de conexiones JDBC. Abstrae a la aplicación
+ del <literal>Datasource</literal> o <literal>DriverManager</literal> subyacente.
+ No se expone a la aplicación, pero puede ser extendido/implementado por
+ el desarrollador.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>TransactionFactory (<literal>org.hibernate.TransactionFactory</literal>)</term>
+ <listitem>
+ <para>
+ (Opcional) Una fábrica de instancias de <literal>Transaction</literal>.
+ No se expone a la aplicación, pero puede ser extendido/implementado por
+ el desarrollador.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><emphasis>Interfaces de Extensión</emphasis></term>
+ <listitem>
+ <para>
+ Hibernate ofrece muchas interfaces de extensión opcional que puedes
+ implementar para modificar a medida el comportamiento de tu capa de persistencia.
+ Para más detalles, mira la documentación de la API.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+
+ <para>
+ Dada una arquitectura "sencilla", la aplicación pasa por alto las APIs
+ de <literal>Transaction</literal>/<literal>TransactionFactory</literal> y/o
+ <literal>ConnectionProvider</literal>, para hablar directamente a JTA o JDBC.
+ </para>
+ </sect1>
+
+ <sect1 id="architecture-states" revision="1">
+ <title>Estados de instancia</title>
+ <para>
+ Una instancia de una clase persistente puede estar en uno de tres estados
+ diferentes, definidos respecto de su <emphasis>contexto de persistencia</emphasis>.
+ El objeto <literal>Session</literal> de Hibernate es el contexto de persistencia:
+ </para>
+
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term>transitorio</term>
+ <listitem>
+ <para>
+ La instancia no está y nunca estuvo asociada con
+ un contexto de persistencia. No tiene identidad persistente
+ (valor de clave primaria).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>persistente</term>
+ <listitem>
+ <para>
+ La instancia está actualmente asociada con un
+ contexto de persistencia. Tiene una identidad persistente
+ (valor de clave primaria) y, quizás, una fila
+ correspondiente en la base de datos. Para un contexto de
+ persistencia en particular, Hibernate <emphasis>garantiza</emphasis>
+ que la identidad persistente es equivalente a la identidad
+ Java (localización en memoria del objeto).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>separado</term>
+ <listitem>
+ <para>
+ La instancia estuvo una vez asociada con un contexto
+ de persistencia, pero ese contexto fue cerrado, o la
+ instancia fue serializada a otro proceso. Tiene una
+ identidad persistente y, quizás, una fila correspondiente
+ en la base de datos. Para las instancias separadas,
+ Hibernate no establece ninguna garantía sobre
+ la relación entre identidad persistente e identidad Java.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect1>
+
+ <sect1 id="architecture-jmx" revision="1">
+ <title>Integración JMX</title>
+
+ <para>
+ JMX es el estándar J2EE para la gestión de componentes Java. Hibernate
+ puede ser gestionado por medio de un servicio estándar JMX.
+ Proveemos una implementación de MBean en la distribución,
+ <literal>org.hibernate.jmx.HibernateService</literal>.
+ </para>
+
+ <para>
+ Para ejemplo de cómo desplegar Hibernate como un servicio JMX en un Servidor
+ de Aplicaciones JBoss, por favor, mira la Guía del Usuario de JBoss.
+ En JBoss AS, tienes además estos beneficios si despliegas usando JMX:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Gestión de Sesión:</emphasis> El ciclo de vida de la <literal>Session</literal>
+ de Hibernate puede estar automáticamente ligado al ámbito de una transacción
+ JTA. Esto significa que ya no tienes que abrir ni cerrar la <literal>Session</literal> manualmente,
+ esto pasa a ser trabajo de un interceptor EJB de JBoss. Además tampoco tienes
+ que preocuparte más de la demarcación de la transacción (a menos que
+ que quieras escribir una capa de persitencia portable, por supuesto, usa la API de
+ <literal>Transaction</literal> de Hibernate para esto). Para acceder a una
+ <literal>Session</literal> llama al <literal>HibernateContext</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Despliegue de HAR:</emphasis> Usualmente despliegas el servicio JMX de Hibernate
+ usando un descriptor de despliegue de servicio de JBoss (en un fichero EAR y/o SAR), que soporta
+ todas las opciones de configuración usuales de una <literal>SessionFactory</literal> de
+ Hibernate. Sin embargo, todavía tienes que nombrar todos tus ficheros de mapeo en el
+ descriptor de despliegue. Si decides usar el depliegue de HAR opcional, JBoss detectará
+ automáticamente todos los ficheros de mapeo en tu fichero HAR.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Para más información sobre estas opciones, consulta la
+ Guía de Usuario del JBoss AS.
+ </para>
+
+ <para>
+ Otra funcionalidad disponible como un servicio JMX son las estadísticas en
+ tiempo de ejecución de Hibernate. Mira <xref linkend="configuration-optional-statistics"/>.
+ </para>
+ </sect1>
+
+ <sect1 id="architecture-jca" revision="1">
+ <title>Soporte JCA:</title>
+ <para>
+ Hiberate puede además ser configurado como un conector JCA. Por favor mira el
+ sitio web para más detalles. Por favor ten en cuenta que el soporte de JCA
+ de Hibernate está aún considerado experimental.
+ </para>
+ </sect1>
+
+</chapter>
+
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/content/association_mapping.xml (from rev 12794, core/trunk/documentation/manual/es-ES/src/main/docbook/modules/association_mapping.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/association_mapping.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/association_mapping.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,527 @@
+<chapter id="associations">
+
+ <title>Mapeos de Asociación</title>
+
+ <sect1 id="assoc-intro" revision="1">
+ <title>Introducción</title>
+
+ <para>
+ Los mapeos de asociación son frecuentemente las cosas mas difíciles
+ de hacer correctamente. En esta sección iremos a través de los casos
+ canónicos uno a uno, comenzando con los mapeos unidireccionales, y considerando
+ luego los casos bidireccionales. Usaremos <literal>Person</literal> y <literal>Address</literal>
+ en todos los ejemplos.
+ </para>
+
+ <para>
+ Clasificaremos las asociaciones por cuanto mapeen o no a una tabla
+ de unión interviniente, y por su multiplicidad.
+ </para>
+
+ <para>
+ Las claves foráneas que aceptan valores nulos (en adelante, nullables)
+ no son consideradas una buena práctica en el modelado tradicional de datos,
+ así que todos nuestros ejemplos usan claves foráneas no nullables.
+ Esto no es un requerimiento de Hibernate, y todos los mapeos funcionarán
+ si quitas las restricciones de nulabilidad.
+ </para>
+
+ </sect1>
+
+ <sect1 id="assoc-unidirectional" revision="1">
+ <title>Asociaciones Unidireccionales</title>
+
+ <sect2 id="assoc-unidirectional-m21">
+ <title>muchos a uno</title>
+
+ <para>
+ Una <emphasis>asociación unidireccional muchos-a-uno</emphasis> es el tipo
+ más común de asociaciones unidireccionales.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <many-to-one name="address"
+ column="addressId"
+ not-null="true"/>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="assoc-unidirectional-121">
+ <title>uno a uno</title>
+
+ <para>
+ Una <emphasis>asociación unidireccional uno-a-uno en una clave primaria</emphasis>
+ es casi idéntica. La única diferencia es la restricción de unicidad
+ de la columna.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <many-to-one name="address"
+ column="addressId"
+ unique="true"
+ not-null="true"/>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ <para>
+ Usualmente, una <emphasis>asociación unidireccional uno-a-uno en una
+ clave primaria</emphasis> usa un generador de id especial. (Observa que hemos
+ invertido el sentido de la asociación en este ejemplo).
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+</class>
+
+<class name="Address">
+ <id name="id" column="personId">
+ <generator class="foreign">
+ <param name="property">person</param>
+ </generator>
+ </id>
+ <one-to-one name="person" constrained="true"/>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( personId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="assoc-unidirectional-12m">
+ <title>uno a muchos</title>
+
+ <para>
+ Una <emphasis>asociación unidireccional uno-a-muchos en una clave foránea</emphasis>
+ es un caso muy inusual, y realmente no está recomendada.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <set name="addresses">
+ <key column="personId"
+ not-null="true"/>
+ <one-to-many class="Address"/>
+ </set>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( addressId bigint not null primary key, personId bigint not null )
+ ]]></programlisting>
+
+ <para>
+ Creemos que es mejor usar una tabla de unión para este tipo de asociación.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="assoc-unidirectional-join" revision="1">
+ <title>Asociaciones unidireccionales con tablas de unión</title>
+
+ <sect2 id="assoc-unidirectional-join-12m">
+ <title>uno a muchos</title>
+
+ <para>
+ Una <emphasis>asociación unidireccional uno-a-muchos en una tabla de unión</emphasis>
+ es más preferible. Observa que especificando <literal>unique="true"</literal>, hemos
+ cambiado la multiplicidad de muchos-a-muchos a uno-a-muchos.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <set name="addresses" table="PersonAddress">
+ <key column="personId"/>
+ <many-to-many column="addressId"
+ unique="true"
+ class="Address"/>
+ </set>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId not null, addressId bigint not null primary key )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="assoc-unidirectional-join-m21">
+ <title>muchos a uno</title>
+
+ <para>
+ Una <emphasis>asociación unidireccional muchos-a-uno en una tabla de unión</emphasis>
+ es bastante común cuando la asociación es opcional.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <join table="PersonAddress"
+ optional="true">
+ <key column="personId" unique="true"/>
+ <many-to-one name="address"
+ column="addressId"
+ not-null="true"/>
+ </join>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="assoc-unidirectional-join-121">
+ <title>uno a uno</title>
+
+ <para>
+ Una <emphasis>asociación unidireccional uno-a-uno en una tabla de unión</emphasis>
+ es inusual en extremo, pero posible.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <join table="PersonAddress"
+ optional="true">
+ <key column="personId"
+ unique="true"/>
+ <many-to-one name="address"
+ column="addressId"
+ not-null="true"
+ unique="true"/>
+ </join>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="assoc-unidirectional-join-m2m">
+ <title>muchos a muchos</title>
+
+ <para>
+ Finalmente, tenemos una <emphasis>asociación unidireccional muchos-a-muchos</emphasis>
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <set name="addresses" table="PersonAddress">
+ <key column="personId"/>
+ <many-to-many column="addressId"
+ class="Address"/>
+ </set>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="assoc-bidirectional" revision="1">
+ <title>Asociaciones Bidireccionales</title>
+
+ <sect2 id="assoc-bidirectional-m21">
+ <title>uno a muchos / muchos a uno</title>
+
+ <para>
+ Una <emphasis>asociación bidireccional muchos-a-uno</emphasis> es
+ el tipo más común de asociación. (Esta es la relación
+ estándar padre/hijo.)
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <many-to-one name="address"
+ column="addressId"
+ not-null="true"/>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+ <set name="people" inverse="true">
+ <key column="addressId"/>
+ <one-to-many class="Person"/>
+ </set>
+</class>]]></programlisting>
+
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="assoc-bidirectional-121">
+ <title>uno a uno</title>
+
+ <para>
+ Una <emphasis>asociación bidireccional uno-a-uno en una clave foránea</emphasis>
+ es bastante común.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <many-to-one name="address"
+ column="addressId"
+ unique="true"
+ not-null="true"/>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+ <one-to-one name="person"
+ property-ref="address"/>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ <para>
+ Una <emphasis>asociación bidireccional uno-a-uno en una clave primaria</emphasis>
+ usa el generador de id especial.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <one-to-one name="address"/>
+</class>
+
+<class name="Address">
+ <id name="id" column="personId">
+ <generator class="foreign">
+ <param name="property">person</param>
+ </generator>
+ </id>
+ <one-to-one name="person"
+ constrained="true"/>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table Address ( personId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="assoc-bidirectional-join" revision="1">
+ <title>Asociaciones bidireccionales con tablas de unión</title>
+
+ <sect2 id="assoc-bidirectional-join-12m">
+ <title>uno a muchos / muchos a uno</title>
+
+ <para>
+ Una <emphasis>asociación bidireccional uno-a-muchos en una tabla de unión</emphasis>.
+ Observa que el <literal>inverse="true"</literal> puede ir a cualquier lado de la asociación,
+ en la colección, o en la unión.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <set name="addresses"
+ table="PersonAddress">
+ <key column="personId"/>
+ <many-to-many column="addressId"
+ unique="true"
+ class="Address"/>
+ </set>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+ <join table="PersonAddress"
+ inverse="true"
+ optional="true">
+ <key column="addressId"/>
+ <many-to-one name="person"
+ column="personId"
+ not-null="true"/>
+ </join>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null primary key )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="assoc-bidirectional-join-121">
+ <title>uno a uno</title>
+
+ <para>
+ Una <emphasis>asociación bidireccional uno-a-uno en una tabla de unión</emphasis>
+ es inusual en extremo, pero posible.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <join table="PersonAddress"
+ optional="true">
+ <key column="personId"
+ unique="true"/>
+ <many-to-one name="address"
+ column="addressId"
+ not-null="true"
+ unique="true"/>
+ </join>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+ <join table="PersonAddress"
+ optional="true"
+ inverse="true">
+ <key column="addressId"
+ unique="true"/>
+ <many-to-one name="address"
+ column="personId"
+ not-null="true"
+ unique="true"/>
+ </join>
+</class>]]></programlisting>
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="assoc-bidirectional-join-m2m">
+ <title>muchos a muchos</title>
+
+ <para>
+ Finalmente, tenemos una <emphasis>asociación bidireccional muchos-a-muchos</emphasis>.
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id" column="personId">
+ <generator class="native"/>
+ </id>
+ <set name="addresses">
+ <key column="personId"/>
+ <many-to-many column="addressId"
+ class="Address"/>
+ </set>
+</class>
+
+<class name="Address">
+ <id name="id" column="addressId">
+ <generator class="native"/>
+ </id>
+ <set name="people" inverse="true">
+ <key column="addressId"/>
+ <many-to-many column="personId"
+ class="Person"/>
+ </set>
+</class>]]></programlisting>
+
+ <programlisting><![CDATA[
+create table Person ( personId bigint not null primary key )
+create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
+create table Address ( addressId bigint not null primary key )
+ ]]></programlisting>
+
+ </sect2>
+
+ </sect1>
+
+
+</chapter>
+
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/content/basic_mapping.xml (from rev 12794, core/trunk/documentation/manual/es-ES/src/main/docbook/modules/basic_mapping.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/basic_mapping.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/basic_mapping.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,3222 @@
+<chapter id="mapping">
+ <title>Mapeo O/R Básico</title>
+
+ <sect1 id="mapping-declaration" revision="1">
+ <title>Declaración de mapeo</title>
+
+ <para>
+ Los mapeos objeto/relacional se definen usualmente en un documento XML.
+ El documento de mapeo está diseñado para ser leíble y
+ editable a mano. El lenguaje de mapeo es Java-céntrico, o sea que los
+ mapeos se construyen alrededor de declaraciones de clases persistentes,
+ no declaraciones de tablas.
+ </para>
+
+ <para>
+ Observa que, incluso aunque muchos usuarios de Hibernate eligen escribir el
+ XML a mano, existe una cantidad de herramientas para generar el documento de
+ mapeo, incluyendo XDoclet, Middlegen y AndroMDA.
+ </para>
+
+ <para>
+ Comencemos por un mapeo de ejemplo:
+ </para>
+
+ <programlisting id="mapping-declaration-ex1" revision="1"><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+ <class name="Cat"
+ table="cats"
+ discriminator-value="C">
+
+ <id name="id">
+ <generator class="native"/>
+ </id>
+
+ <discriminator column="subclass"
+ type="character"/>
+
+ <property name="weight"/>
+
+ <property name="birthdate"
+ type="date"
+ not-null="true"
+ update="false"/>
+
+ <property name="color"
+ type="eg.types.ColorUserType"
+ not-null="true"
+ update="false"/>
+
+ <property name="sex"
+ not-null="true"
+ update="false"/>
+
+ <property name="litterId"
+ column="litterId"
+ update="false"/>
+
+ <many-to-one name="mother"
+ column="mother_id"
+ update="false"/>
+
+ <set name="kittens"
+ inverse="true"
+ order-by="litter_id">
+ <key column="mother_id"/>
+ <one-to-many class="Cat"/>
+ </set>
+
+ <subclass name="DomesticCat"
+ discriminator-value="D">
+
+ <property name="name"
+ type="string"/>
+
+ </subclass>
+
+ </class>
+
+ <class name="Dog">
+ <!-- mapping for Dog could go here -->
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Discutiremos ahora el contenido del documento de mapeo. Describiremos sólo los
+ elementos y atributos que son usados por Hibernate en tiempo de ejecución. El
+ documento de mapeo contiene además algunos atributos y elementos extra opcionales
+ que afectan los esquemas de base de datos exportados por la herramienta de exportación
+ de esquemas. (Por ejemplo, el atributo <literal>not-null</literal>.)
+ </para>
+
+
+
+ <sect2 id="mapping-declaration-doctype" revision="2">
+ <title>Doctype</title>
+
+ <para>
+ Todos los mapeos XML deben declarar el doctype mostrado. El DTD actual puede
+ ser encontrado en el URL mencionado arriba, en el directorio
+ <literal>hibernate-x.x.x/src/org/hibernate</literal>, o en <literal>hibernate3.jar</literal>.
+ Hibernate siempre buscará el DTD primero en el classpath. Si experimentas
+ búsquedas del DTD usando una conexión de Internet, chequea tu declaración
+ de DTD contra la contenida en el classpath.
+ </para>
+ </sect2>
+
+ <sect2 id="mapping-declaration-mapping" revision="3">
+ <title>hibernate-mapping</title>
+
+ <para>
+ Este elemento tiene muchos atributos opcionales. Los atributos <literal>schema</literal>
+ y <literal>catalog</literal> especifican que las tablas a las que se refiere en el mapeo
+ pertenecen al esquema y/o catálogo mencionado(s). De especificarse, los nombres de
+ tablas serán cualificados por el nombre de esquema y catálogo dados.
+ De omitirse, los nombres de tablas no serán cualificados. El atributo
+ <literal>default-cascade</literal> especifica qué estilo de cascada debe asumirse
+ para las propiedades y colecciones que no especifican un atributo <literal>cascade</literal>.
+ El atributo <literal>auto-import</literal> nos permite usar nombres de clase sin cualificar
+ en el lenguaje de consulta, por defecto.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="hm1" coords="2 55"/>
+ <area id="hm2" coords="3 55"/>
+ <area id="hm3" coords="4 55"/>
+ <area id="hm4" coords="5 55"/>
+ <area id="hm5" coords="6 55"/>
+ <area id="hm6" coords="7 55"/>
+ <area id="hm7" coords="8 55"/>
+ </areaspec>
+ <programlisting><![CDATA[<hibernate-mapping
+ schema="schemaName"
+ catalog="catalogName"
+ default-cascade="cascade_style"
+ default-access="field|property|ClassName"
+ default-lazy="true|false"
+ auto-import="true|false"
+ package="package.name"
+ />]]></programlisting>
+ <calloutlist>
+ <callout arearefs="hm1">
+ <para>
+ <literal>schema</literal> (opcional): El nombre de un esquema de la base de datos.
+ </para>
+ </callout>
+ <callout arearefs="hm2">
+ <para>
+ <literal>catalog</literal> (opcional): El nombre de un catálogo de la base de datos.
+ </para>
+ </callout>
+ <callout arearefs="hm3">
+ <para>
+ <literal>default-cascade</literal> (opcional - por defecto a <literal>none</literal>):
+ Un estilo de cascada por defecto.
+ </para>
+ </callout>
+ <callout arearefs="hm4">
+ <para>
+ <literal>default-access</literal> (opcional - por defecto a <literal>property</literal>):
+ La estrategia que Hibernate debe usar para acceder a todas las propiedades.
+ Puede ser una implementación personalizada de <literal>PropertyAccessor</literal>.
+ </para>
+ </callout>
+ <callout arearefs="hm5">
+ <para>
+ <literal>default-lazy</literal> (opcional - por defecto a <literal>true</literal>):
+ El valor por defecto para los atributos <literal>lazy</literal> de mapeos de clase
+ y colleción no especificados.
+ </para>
+ </callout>
+ <callout arearefs="hm6">
+ <para>
+ <literal>auto-import</literal> (opcional - por defecto a <literal>true</literal>):
+ Especifica si podemos usar nombres de clases no cualificados (de clases en este mapeo)
+ en el lenguaje de consulta.
+ </para>
+ </callout>
+ <callout arearefs="hm7">
+ <para>
+ <literal>package</literal> (opcional): Especifica un prefijo de paquete a asumir
+ para los nombres no cualificados de clase en el documento de mapeo.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Si tienes dos clases persistentes con el mismo nombre (sin cualificar), debes establecer
+ <literal>auto-import="false"</literal>. Hibernate lanzará una excepción si
+ intentas asignar dos clases al mismo nombre "importado".
+ </para>
+
+ <para>
+ Observa que el elemento <literal>hibernate-mapping</literal> te permite anidar
+ muchos mapeos <literal><class></literal> persistentes, como se muestra arriba.
+ Sin embargo, es una buena práctica (y se espera de algunas herramientas) mapear
+ sólo a una sola clase persistente (o a una sola jerarquía de clases) en
+ un fichero de mapeo y nombrarlo después de la superclase persistente;
+ por ejemplo, <literal>Cat.hbm.xml</literal>, <literal>Dog.hbm.xml</literal>,
+ o, si se usa herencia, <literal>Animal.hbm.xml</literal>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-class" revision="3">
+ <title>class</title>
+
+ <para>
+ Puedes declarar una clase persistente usando el elemento <literal>class</literal>:
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="class1" coords="2 55"/>
+ <area id="class2" coords="3 55" />
+ <area id="class3" coords="4 55"/>
+ <area id="class4" coords="5 55" />
+ <area id="class5" coords="6 55"/>
+ <area id="class6" coords="7 55" />
+ <area id="class7" coords="8 55"/>
+ <area id="class8" coords="9 55" />
+ <area id="class9" coords="10 55" />
+ <area id="class10" coords="11 55"/>
+ <area id="class11" coords="12 55"/>
+ <area id="class12" coords="13 55"/>
+ <area id="class13" coords="14 55"/>
+ <area id="class14" coords="15 55"/>
+ <area id="class15" coords="16 55"/>
+ <area id="class16" coords="17 55"/>
+ <area id="class17" coords="18 55"/>
+ <area id="class18" coords="19 55"/>
+ <area id="class19" coords="20 55"/>
+ <area id="class20" coords="21 55"/>
+ <area id="class21" coords="22 55"/>
+ </areaspec>
+ <programlisting><![CDATA[<class
+ name="ClassName"
+ table="tableName"
+ discriminator-value="discriminator_value"
+ mutable="true|false"
+ schema="owner"
+ catalog="catalog"
+ proxy="ProxyInterface"
+ dynamic-update="true|false"
+ dynamic-insert="true|false"
+ select-before-update="true|false"
+ polymorphism="implicit|explicit"
+ where="arbitrary sql where condition"
+ persister="PersisterClass"
+ batch-size="N"
+ optimistic-lock="none|version|dirty|all"
+ lazy="true|false"
+ entity-name="EntityName"
+ check="arbitrary sql check condition"
+ rowid="rowid"
+ subselect="SQL expression"
+ abstract="true|false"
+ node="element-name"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="class1">
+ <para>
+ <literal>name</literal> (opcional): El nombre completamente cualificado de la clase
+ Java persistente (o interface). Si este atributo es omitido, se asume que el mapeo
+ es para una entidad non-POJO.
+ </para>
+ </callout>
+ <callout arearefs="class2">
+ <para>
+ <literal>table</literal> (opcional - por defecto al nombre no cualificado de la clase):
+ El nombre de su tabla en base de datos.
+ </para>
+ </callout>
+ <callout arearefs="class3">
+ <para>
+ <literal>discriminator-value</literal> (opcional - por defecto al nombre de la clase):
+ Un valor que distingue subclases individuales, usado para el comportamiento
+ polimórfico. Los valores aceptables incluyen <literal>null</literal>
+ y <literal>not null</literal>.
+ </para>
+ </callout>
+ <callout arearefs="class4">
+ <para>
+ <literal>mutable</literal> (opcional, por defecto a <literal>true</literal>):
+ Especifica que las instancias de la clase (no) son mutables.
+ </para>
+ </callout>
+ <callout arearefs="class5">
+ <para>
+ <literal>schema</literal> (opcional): Sobreescribe el nombre de esquema especificado
+ por el elemento raíz <literal><hibernate-mapping></literal>.
+ </para>
+ </callout>
+ <callout arearefs="class6">
+ <para>
+ <literal>catalog</literal> (opcional): Sobreescribe el nombre de catálogo
+ especificado por el elemento raíz <literal><hibernate-mapping></literal>.
+ </para>
+ </callout>
+ <callout arearefs="class7">
+ <para>
+ <literal>proxy</literal> (opcional): Especifica una interface a usar para proxies
+ de inicialización perezosa. Puedes especificar el nombre mismo de la clase.
+ </para>
+ </callout>
+ <callout arearefs="class8">
+ <para>
+ <literal>dynamic-update</literal> (opcional, por defecto a <literal>false</literal>):
+ Especifica que el SQL <literal>UPDATE</literal> debe ser generado en tiempo de
+ ejecución y contener solamente aquellas columnas cuyo valor haya cambiado.
+ </para>
+ </callout>
+ <callout arearefs="class9">
+ <para>
+ <literal>dynamic-insert</literal> (opcional, por defecto a <literal>false</literal>):
+ Especifica que el SQL <literal>INSERT</literal> debe ser generado en tiempo de
+ ejecución y contener solamente aquellas columnas cuyo valores no son nulos.
+ </para>
+ </callout>
+ <callout arearefs="class10">
+ <para>
+ <literal>select-before-update</literal> (opcional, por defecto a <literal>false</literal>):
+ Especifica que Hibernate <emphasis>nunca</emphasis> debe realizar un SQL <literal>UPDATE</literal>
+ a menos que se tenga certeza que un objeto haya sido modificado realmente.
+ En ciertos casos, (realmente, sólo cuando un objeto transitorio ha sido asociado
+ con una sesión nueva usando <literal>update()</literal>), esto significa que Hibernate
+ realizará una SQL <literal>SELECT</literal> extra para determinar si un
+ <literal>UPDATE</literal> es realmente requerido.
+ </para>
+ </callout>
+ <callout arearefs="class11">
+ <para>
+ <literal>polymorphism</literal> (opcional, por defecto a <literal>implicit</literal>):
+ Determina si se usa polimorfismo de consulta implícito o explícito.
+ </para>
+ </callout>
+ <callout arearefs="class12">
+ <para>
+ <literal>where</literal> (opcional) especifica una condición SQL <literal>WHERE</literal>
+ arbitraria paraa ser usada al recuperar objetos de esta clase.
+ </para>
+ </callout>
+ <callout arearefs="class13">
+ <para>
+ <literal>persister</literal> (opcional): Especifica un <literal>ClassPersister</literal>
+ personalizado.
+ </para>
+ </callout>
+ <callout arearefs="class14">
+ <para>
+ <literal>batch-size</literal> (opcional, por defecto a <literal>1</literal>)
+ especifica un "tamaño de lote" para traer instancias de esta clase por
+ identificador.
+ </para>
+ </callout>
+ <callout arearefs="class15">
+ <para>
+ <literal>optimistic-lock</literal> (opcional, por defecto a <literal>version</literal>):
+ Determina la estrategia optimista de bloqueo.
+ </para>
+ </callout>
+ <callout arearefs="class16">
+ <para>
+ <literal>lazy</literal> (opcional):
+ La recuperación perezosa puede ser deshabilitada por completo estableciendo
+ <literal>lazy="false"</literal>.
+ </para>
+ </callout>
+ <callout arearefs="class17">
+ <para>
+ <literal>entity-name</literal> (opcional): Hibernate3 permite que una clase sea
+ mapeada varias veces (potencialmente a tablas diferentes), y permite que los mapeos
+ de entidad sean representados por Maps o XML al nivel de Java. En estos casos,
+ debes proveer un nombre explícito arbitrario para la entidad.
+ Para más información, mira
+ <xref linkend="persistent-classes-dynamicmodels"/> y <xref linkend="xml"/>.
+ </para>
+ </callout>
+ <callout arearefs="class18">
+ <para>
+ <literal>check</literal> (opcional): Una expresión SQL usada para generar
+ una restricción <emphasis>check</emphasis> multi-fila para la generación
+ automática de esquema.
+ </para>
+ </callout>
+ <callout arearefs="class19">
+ <para>
+ <literal>rowid</literal> (opcional): Hibernate puede usar los llamados ROWIDs en las
+ bases de datos que los soporten. Por ejemplo, en Oracle, Hibernate puede usar la columna
+ extra <literal>rowid</literal> para actualizaciones rápidas si estableces esta
+ opción a <literal>rowid</literal>. Un ROWID es un detalle de implementación
+ y representa la posición física de la tupla almacenada.
+ </para>
+ </callout>
+ <callout arearefs="class20">
+ <para>
+ <literal>subselect</literal> (opcional): Mapea una entidad inmutable y de sólo
+ lectura a una subselect de base de datos. Es útil si quieres tener una vista
+ en vez de una tabla base, pero no tienes vistas. Mira debajo para más información.
+ </para>
+ </callout>
+ <callout arearefs="class21">
+ <para>
+ <literal>abstract</literal> (opcional): Usado para marcar superclases abstractas en
+ jerarquías <literal><union-subclass></literal>.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Es perfectamente aceptable que la clase persistente mencionada sea una interface.
+ Entonces declararías clases que implementan esa interface usando el elemento
+ <literal><subclass></literal>. Puedes persistir cualquier clase interna
+ <emphasis>estática</emphasis>. Debes especificar el nombre de la clase usando la forma
+ estándar. Por ejemplo, <literal>eg.Foo$Bar</literal>.
+ </para>
+
+ <para>
+ Las clases inmutables, <literal>mutable="false"</literal>, no pueden ser actualizadas o
+ borradas por la aplicación. Esto permite a Hibernate hacer ciertas optimizaciones
+ menores de rendimiento.
+ </para>
+
+ <para>
+ El atributo opcional <literal>proxy</literal> habilita la inicialización postergada
+ de instancias persistentes de la clase. Hibernate inicialmente retornará proxies
+ CGLIB que implementan la interface mencionada. El objeto persistente real será
+ cargado cuando se invoque un método del proxy. Mira "Proxies para Inicialización
+ Postergada" debajo.
+ </para>
+
+ <para>
+ Por polimorfismo <emphasis>implícito</emphasis> se entiende que las instancias de la clase
+ serán devueltas por una consulta que mencione cualquier superclase, o interface implementada,
+ o la clase misma; y que las instancias de cualquier subclase de la clase serán devueltas
+ por una clase que mencione a la clase en sí.
+ Por polimorfismo <emphasis>explícito</emphasis> se entiende que instancias de la clase
+ serán devueltas sólo por consultas que mencionen explícitamente la clase;
+ y que las consultas que mencionen la clase devolverán sólo instancias de subclases
+ mapeadas dentro de esta declaración <literal><class></literal> como una
+ <literal><subclass></literal> o <literal><joined-subclass></literal>.
+ Para la mayoría de los propósitos el defecto,
+ <literal>polymorphism="implicit"</literal>, resulta apropiado.
+ El polimorfismo explícito es útil cuando dos clases diferentes están
+ mapeadas a la misma tabla (esto permite tener una clase "liviana" que contenga un subconjunto
+ de columnas de la tabla).
+ </para>
+
+ <para>
+ El atributo <literal>persister</literal> te permite personalizar la estrategia de persistencia
+ para la clase. Puedes, por ejemplo, especificar tu propia subclase de
+ <literal>org.hibernate.persister.EntityPersister</literal> o incluso puedes proveer una implementación
+ completamente nueva de la interface <literal>org.hibernate.persister.ClassPersister</literal> que implemente
+ la persistencia por medio, por ejemplo, de llamadas a procedimientos almacenados, serialización a
+ ficheros planos o LDAP. Para un ejemplo simple (de persistencia a una <literal>Hashtable</literal>) mira
+ <literal>org.hibernate.test.CustomPersister</literal>.
+ </para>
+
+ <para>
+ Observa que los valores de <literal>dynamic-update</literal> y <literal>dynamic-insert</literal>
+ no son heredados por las subclases y por lo tanto deben especificarse en los elementos
+ <literal><subclass></literal> o <literal><joined-subclass></literal>.
+ Estos ajustes pueden incrementar el rendimiento en algunos casos, pero podrían mermarlo en otros.
+ Ten juicio en su uso.
+ </para>
+
+ <para>
+ Generalmente el uso de <literal>select-before-update</literal> disminuirá el rendimiento.
+ Es muy útil prevenir que se llame innecesariamente a un disparador de actualización de
+ base de datos al volver a unir un grafo de instancias separadas a una <literal>Session</literal>.
+ </para>
+
+ <para>
+ Si habilitas <literal>dynamic-update</literal>, tendrás opción de estrategias
+ de bloqueo optimistas:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>version</literal> chequea las columnas de versión/timestamp
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>all</literal> chequea todas las columnas
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>dirty</literal> chequea las columnas modificadas, permitiendo algunas
+ actualizaciones concurrentes
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>none</literal> no usa bloqueo optimista
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Recomendamos <emphasis>muy</emphasis> fuertemente que uses columnas de
+ versión/timestamp para bloqueo optimista con Hibernate. Esta es la estrategia
+ óptima con respecto al rendimiento y es la única estrategia que maneja
+ correctamente las modificaciones hechas a las instancias separadas.
+ (por ejemplo, cuando se usa <literal>Session.merge()</literal>).
+ </para>
+
+ <para>
+ Para un mapeo de Hibernate, no hay diferencia entre una vista y una tabla base.
+ Como se supone esto es transparente a nivel de base de datos (observa que algunos
+ DBMS no soportan correctamente las vistas, especialmente con las actualizaciones).
+ A veces quieres usar una vista, pero no puedes crear una en la base de datos
+ (por ejemplo, con un esquema heredado). En este caso, puedes mapear una entidad inmutable
+ de sólo lectura a una expresión de subconsulta SQL dada.
+ </para>
+
+ <programlisting><![CDATA[<class name="Summary">
+ <subselect>
+ select item.name, max(bid.amount), count(*)
+ from item
+ join bid on bid.item_id = item.id
+ group by item.name
+ </subselect>
+ <synchronize table="item"/>
+ <synchronize table="bid"/>
+ <id name="name"/>
+ ...
+</class>]]></programlisting>
+
+ <para>
+ Declara las tablas con las que sincronizar esta entidad, asegurando que el auto-flush
+ ocurre correctamente, y que las consultas contra la entidad derivada no devuelven datos
+ desactualizados. El <literal><subselect></literal> está disponible tanto
+ como un atributo o como un elemento anidado de mapeo.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-id" revision="3">
+ <title>id</title>
+
+ <para>
+ Las clases mapeadas <emphasis>deben</emphasis> declarar la columna de clave primaria de la tabla
+ de la base de datos. En la mayoría de los casos tendrá también una propiedad
+ estilo Javabeans que tenga el identificador único de una instancia. El elemento
+ <literal><id></literal> define el mapeo de esa propiedad a la columna de clave primaria.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="id1" coords="2 70"/>
+ <area id="id2" coords="3 70" />
+ <area id="id3" coords="4 70"/>
+ <area id="id4" coords="5 70" />
+ <area id="id5" coords="6 70" />
+ </areaspec>
+ <programlisting><![CDATA[<id
+ name="propertyName"
+ type="typename"
+ column="column_name"
+ unsaved-value="null|any|none|undefined|id_value"
+ access="field|property|ClassName"
+ node="element-name|@attribute-name|element/@attribute|.">
+
+ <generator class="generatorClass"/>
+</id>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="id1">
+ <para>
+ <literal>name</literal> (opcional): El nombre de la propiedad del indentificador.
+ </para>
+ </callout>
+ <callout arearefs="id2">
+ <para>
+ <literal>type</literal> (opcional): Un nombre que indica el tipo Hibernate.
+ </para>
+ </callout>
+ <callout arearefs="id3">
+ <para>
+ <literal>column</literal> (opcional - por defecto al nombre de la propiedad):
+ El nombre de la columna de clave primaria.
+ </para>
+ </callout>
+ <callout arearefs="id4">
+ <para>
+ <literal>unsaved-value</literal> (opcional - por defecto al valor "sensible"):
+ Una valor de la propiedad identificadora que indica que una instancia está
+ recién instanciada (sin salvar), distinguiéndola de instancias separadas
+ que fueran salvadas o cargadas en una sesión previa.
+ </para>
+ </callout>
+ <callout arearefs="id5">
+ <para>
+ <literal>access</literal> (opcional - por defecto a <literal>property</literal>):
+ La estrategia que Hibernate debe usar para acceder al valor de la propiedad.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Si se omite el atributo <literal>name</literal>, se asume que la clase no tiene propiedad
+ identificadora.
+ </para>
+
+ <para>
+ El atributo <literal>unsaved-value</literal> es importante! Si la propiedad identificadora de tu
+ clase no tiene por defecto el valor por defecto normal de Java (null o cero), entonces debes especificar
+ el valor por defecto real.
+ </para>
+
+ <para>
+ Hay una declaración <literal><composite-id></literal> alternativa para permitir acceso
+ a datos heredados con claves compuestas. Desalentamos fuertemente su uso para cualquier otra cosa.
+ </para>
+
+ <sect3 id="mapping-declaration-id-generator" revision="2">
+ <title>Generator</title>
+
+ <para>
+ El elemento hijo opcional <literal><generator></literal> nombra una clase Java
+ usada en generar identificadores únicos para instancias de la clase persistente.
+ De requerirse algún parámetro para configurar o inicializar la instancia del generador,
+ se pasa usando el elemento <literal><param></literal>.
+ </para>
+
+ <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+ <generator class="org.hibernate.id.TableHiLoGenerator">
+ <param name="table">uid_table</param>
+ <param name="column">next_hi_value_column</param>
+ </generator>
+</id>]]></programlisting>
+
+ <para>
+ Todos los generadores implementan la interface <literal>org.hibernate.id.IdentifierGenerator</literal>.
+ Esta es una interface muy simple; algunas aplicaciones pueden escoger proveer sus propias
+ implementaciones especializadas. Sin embargo, Hibernate provee un rango de implementaciones
+ prefabricadas. Hay nombres alias de atajo para los generadores prefabricados:
+ <variablelist>
+ <varlistentry>
+ <term><literal>increment</literal></term>
+ <listitem>
+ <para>
+ genera indentificadores de tipo <literal>long</literal>, <literal>short</literal> o
+ <literal>int</literal> que sólo son únicos cuando ningún otro proceso
+ está insertando datos en la misma tabla. <emphasis>No usar en un cluster.</emphasis>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>identity</literal></term>
+ <listitem>
+ <para>
+ soporta columnas de identidad en DB2, MySQL, MS SQL Server, Sybase y
+ HypersonicSQL. El identificador devuelto es de tipo <literal>long</literal>,
+ <literal>short</literal> o <literal>int</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>sequence</literal></term>
+ <listitem>
+ <para>
+ usa una secuencia en DB2, PostgreSQL, Oracle, SAP DB, McKoi o un generador
+ en Interbase. El identificador devuelto es de tipo <literal>long</literal>,
+ <literal>short</literal> o <literal>int</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>hilo</literal></term>
+ <listitem>
+ <para id="mapping-declaration-id-hilodescription" revision="1">
+ usa un algoritmo alto/bajo para generar eficientemente identificadores de tipo
+ <literal>long</literal>, <literal>short</literal> o <literal>int</literal>,
+ dada una tabla y columna como fuente de valores altos (por defecto
+ <literal>hibernate_unique_key</literal> y <literal>next_hi</literal> respectivamente).
+ El algoritmo alto/bajo genera identificadores que son únicos sólo para una
+ base de datos particular.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>seqhilo</literal></term>
+ <listitem>
+ <para>
+ usa un algoritmo alto/bajo para generar eficientemente identificadores de tipo
+ <literal>long</literal>, <literal>short</literal> o <literal>int</literal>,
+ dada una secuencia de base de datos.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>uuid</literal></term>
+ <listitem>
+ <para>
+ usa un algoritmo UUID de 128 bits para generar identificadore de tipo
+ cadena, únicos en una ref (se usa la direccón IP). El UUID
+ se codifica como una cadena hexadecimal de 32 dígitos de largo.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>guid</literal></term>
+ <listitem>
+ <para>
+ usa una cadena GUID generada por base de datos en MS SQL Server y MySQL.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>native</literal></term>
+ <listitem>
+ <para>
+ selecciona <literal>identity</literal>, <literal>sequence</literal> o
+ <literal>hilo</literal> dependiendo de las capacidades de la base de datos
+ subyacente.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>assigned</literal></term>
+ <listitem>
+ <para>
+ deja a la aplicación asignar un identificador al objeto antes
+ de que se llame a <literal>save()</literal>. Esta es la estrategia
+ por defecto si no se especifica un elemento <literal><generator></literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>select</literal></term>
+ <listitem>
+ <para>
+ recupera una clave primaria asignada por un disparador de base de datos
+ seleccionando la fila por alguna clave única y recuperando el valor de
+ la clave primaria.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>foreign</literal></term>
+ <listitem>
+ <para>
+ usa el identificador de otro objeto asociado. Generalmente usado en conjuncón
+ a una asociacón de clave primaria <literal><uno-a-uno></literal>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ </para>
+ </sect3>
+
+ <sect3 id="mapping-declaration-id-hilo" revision="1">
+ <title>Algoritmo alto/bajo</title>
+ <para>
+ Los generadores <literal>hilo</literal> y <literal>seqhilo</literal> proveen dos implementaciones
+ alternativas del algoritmo alto/bajo, un enfoque favorito en generación de identificadores.
+ La primera implementación requiere de una tabla "especial" de base de datos para tener el siguiente
+ valor "alto" disponible.
+ La segunda usa una secuencia del estilo de Oracle (donde se soporte).
+ </para>
+
+ <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+ <generator class="hilo">
+ <param name="table">hi_value</param>
+ <param name="column">next_value</param>
+ <param name="max_lo">100</param>
+ </generator>
+</id>]]></programlisting>
+
+ <programlisting><![CDATA[<id name="id" type="long" column="cat_id">
+ <generator class="seqhilo">
+ <param name="sequence">hi_value</param>
+ <param name="max_lo">100</param>
+ </generator>
+</id>]]></programlisting>
+
+ <para>
+ Desafortunadamente, no puedes usar <literal>hilo</literal> cuando le proveas tu propia
+ <literal>Connection</literal> a Hibernate. Cuando Hibernate está usando un datasource
+ del servidor de aplicaciones para obtener conexiones alistadas con JTA, debes configurar
+ correctamente el <literal>hibernate.transaction.manager_lookup_class</literal>.
+ </para>
+ </sect3>
+
+ <sect3 id="mapping-declaration-id-uuid">
+ <title>Algoritmo UUID</title>
+ <para>
+ El UUID contiene: la dirección IP, el instante de arranque de la JVM
+ (con una precisión de un cuarto de segundo), el tiempo de sistema y un valor
+ de contador (único en la JVM). No es posible obtener una dirección MAC o
+ una dirección de memoria desde código Java, así que esto es lo mejor
+ que podemos hacer sin usar JNI.
+ </para>
+ </sect3>
+
+ <sect3 id="mapping-declaration-id-sequences">
+ <title>Columnas de identidad y secuencias</title>
+ <para>
+ Para las bases de datos que soportan columnas de identidad (DB2, MySQL, Sybase, MS SQL),
+ puedes usar generación de claves <literal>identity</literal>. Para las bases de datos
+ que soportan secuencias (DB2, Oracle, PostgreSQL, Interbase, McKoi, SAP DB) puedes usar la generación
+ de claves del estilo <literal>sequence</literal>. Ambas estrategias requieren dos consultas SQL
+ para insertar un nuevo objeto.
+ </para>
+
+ <programlisting><![CDATA[<id name="id" type="long" column="person_id">
+ <generator class="sequence">
+ <param name="sequence">person_id_sequence</param>
+ </generator>
+</id>]]></programlisting>
+
+ <programlisting><![CDATA[<id name="id" type="long" column="person_id" unsaved-value="0">
+ <generator class="identity"/>
+</id>]]></programlisting>
+
+ <para>
+ Para desarrollos multiplataforma, la estrategia <literal>native</literal>
+ eiligirá de entre las estrategias <literal>identity</literal>,
+ <literal>sequence</literal> y <literal>hilo</literal>, dependiendo de las capacidades
+ de la base de datos subyacentes.
+ </para>
+ </sect3>
+
+ <sect3 id="mapping-declaration-id-assigned">
+ <title>Identificadores asignados</title>
+ <para>
+ Si quieres que la aplicación asigne los identificadores (en contraposición
+ a que los genere Hibernate), puedes usar el generador <literal>assigned</literal>.
+ Este generador especial usará el valor identificador ya asignado a la
+ propiedad identificadora del objeto. Este generador se usa cuandola clave primaria es
+ una clave natural en vez de una clave sustituta. Este es el comportamiento por defecto si
+ no especificas un elemento <literal><generator></literal>.
+ </para>
+
+ <para>
+ Elegir el generador <literal>assigned</literal> hace que Hibernate use
+ <literal>unsaved-value="undefined"</literal>, forzando a Hibernate a ir
+ a la base de datos para determinar si una instancia es transitoria o separada,
+ a menos que haya una propiedad de versión o timestamp, o que tu definas
+ <literal>Interceptor.isUnsaved()</literal>.
+ </para>
+ </sect3>
+
+ <sect3 id="mapping-declaration-id-select">
+ <title>Claves primarias asignadas por disparadores</title>
+ <para>
+ Para esquemas heredados solamente (Hibernate no genera DDL con disparadores).
+ </para>
+
+ <programlisting><![CDATA[<id name="id" type="long" column="person_id">
+ <generator class="select">
+ <param name="key">socialSecurityNumber</param>
+ </generator>
+</id>]]></programlisting>
+
+ <para>
+ En el ejemplo de arriba, hay una propiedad ánica llamada
+ <literal>socialSecurityNumber</literal> definida por la clase, como
+ una clave natural, y una clave sustituta llamada <literal>person_id</literal>
+ cuyo valor es generado por un disparador.
+ </para>
+
+ </sect3>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-compositeid" revision="2">
+ <title>composite-id</title>
+
+ <programlisting><![CDATA[<composite-id
+ name="propertyName"
+ class="ClassName"
+ unsaved-value="undefined|any|none"
+ access="field|property|ClassName"
+ node="element-name|.">
+
+ <key-property name="propertyName" type="typename" column="column_name"/>
+ <key-many-to-one name="propertyName class="ClassName" column="column_name"/>
+ ......
+</composite-id>]]></programlisting>
+
+ <para>
+ Para una tabla con clave compuesta, puedes mapear múltiples propiedades
+ de la clase como propiedades identificadoras. El elemento <literal><composite-id></literal>
+ acepta los mapeos de propiedad <literal><key-property></literal> y
+ los mapeos <literal><key-many-to-one></literal> como elementos hijo.
+ </para>
+
+ <programlisting><![CDATA[<composite-id>
+ <key-property name="medicareNumber"/>
+ <key-property name="dependent"/>
+</composite-id>]]></programlisting>
+
+ <para>
+ Tu clase persistente <emphasis>debe</emphasis> sobreescribir <literal>equals()</literal>
+ y <literal>hashCode()</literal> para implementar igualdad de identificador compuesto.
+ Debe también implementar <literal>Serializable</literal>.
+ </para>
+
+ <para>
+ Desafortunadamente, este enfoque de identificadores compuestos significa que un objeto
+ persistente es su propio identificador. No existe otra "asa" conveniente más que el
+ objeto mismo. Debes instanciar una instancia de la clase misma y poblar sus propiedades
+ identificadoras antes que puedas <literal>load()</literal> el estado persistente asociado
+ a una clave compuesta. Describiremos un enfoque mucho más conveniente donde el identificador
+ compuesto está implementado como una clase separada en <xref linkend="components-compositeid"/>.
+ Los atributos descriptos debajo solamente se aplican a este enfoque alternativo:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>name</literal> (opcional): Una propiedad de tipo componente que tiene el identificador
+ compuesto (ver siguiente sección).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>class</literal> (opcional - por defecto al tipo de la propiedad determinado
+ por reflección): La clase del componente usado como identificador compuesto (ver siguiente sección).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>unsaved-value</literal> (opcional - por defecto a <literal>undefined</literal>):
+ Indica que las instancias transitorias deben ser consideradas como recién instanciadas,
+ si se establece a <literal>any</literal>, o separadas, si se establece a <literal>none</literal>.
+ Lo mejor
+
+ Indicates that transient instances should be considered newly instantiated, if set
+ to <literal>any</literal>, or detached, if set to <literal>none</literal>.
+ Lo mejor en todos los casos es dejar el valor por defecto.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-discriminator" revision="3">
+ <title>discriminator</title>
+
+ <para>
+ El elemento <literal><discriminator></literal> es requerido para la persistencia
+ polimórfica usando la estrategia de mapeo de tabla-por-jerarquía-de-clases y
+ declara una columna discriminadora de la tabla. La columna discriminidora contiene valores
+ de marca que le dicen a la capa de persistencia qué subclase instanciar para una fila
+ en particular. Un conjunto restringido de tipos puede ser usado:
+ <literal>string</literal>, <literal>character</literal>, <literal>integer</literal>,
+ <literal>byte</literal>, <literal>short</literal>, <literal>boolean</literal>,
+ <literal>yes_no</literal>, <literal>true_false</literal>.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="discriminator1" coords="2 60"/>
+ <area id="discriminator2" coords="3 60" />
+ <area id="discriminator3" coords="4 60" />
+ <area id="discriminator4" coords="5 60" />
+ <area id="discriminator5" coords="6 60" />
+ </areaspec>
+ <programlisting><![CDATA[<discriminator
+ column="discriminator_column"
+ type="discriminator_type"
+ force="true|false"
+ insert="true|false"
+ formula="arbitrary sql expression"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="discriminator1">
+ <para>
+ <literal>column</literal> (opcional - por defecto a <literal>class</literal>) el
+ nombre de la columna discriminadora.
+ </para>
+ </callout>
+ <callout arearefs="discriminator2">
+ <para>
+ <literal>type</literal> (opcional - por defecto a <literal>string</literal>) un
+ nombre que indique el tipo Hibernate
+ </para>
+ </callout>
+ <callout arearefs="discriminator3">
+ <para>
+ <literal>force</literal> (optconal - por defecto a <literal>false</literal>)
+ "fuerza" a Hibernate a especificar valores discriminadores permitidos incluso
+ cuando se recuperan todas las instancias de la clase raíz.
+ </para>
+ </callout>
+ <callout arearefs="discriminator4">
+ <para>
+ <literal>insert</literal> (opcional - por defecto a <literal>true</literal>)
+ establezca este a <literal>false</literal> si tu columna discriminadora es
+ también parte de un identificador mapeado compuesto. (Le dice a Hibernate
+ que no incluya la columna en los SQL <literal>INSERT</literal>s.)
+ </para>
+ </callout>
+ <callout arearefs="discriminator5">
+ <para>
+ <literal>formula</literal> (opcional) una expresión SQL arbitraria que
+ es ejecutada cuando un tipo tenga que ser evaluado. Permite dicriminación
+ basada en el contenido.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Los valores reales de la columna discriminadora están especificados por
+ el atributo <literal>discriminator-value</literal> de los elementos
+ <literal><class></literal> y <literal><subclass></literal>.
+ </para>
+
+ <para>
+ El atributo <literal>force</literal> es (sólo) útil si la tabla contiene
+ filas con valores discriminadores "extra" que no están mapeados a la clase
+ persistente. Generalmente este no es el caso.
+ </para>
+
+ <para>
+ Usando el atributo <literal>formula</literal> puedes declarar una expresión SQL
+ arbitraria que será usada para evaluar el tipo de una fila:
+ </para>
+
+ <programlisting><![CDATA[<discriminator
+ formula="case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end"
+ type="integer"/>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-version" revision="1">
+ <title>version (opcional)</title>
+
+ <para>
+ El elemento <literal><version></literal> es opcional e indica que la
+ tabla contiene datos versionados. Esto es particularmente útil si planeas
+ usar <emphasis>transacciones largas</emphasis> (ver debajo).
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="version1" coords="2 70"/>
+ <area id="version2" coords="3 70"/>
+ <area id="version3" coords="4 70"/>
+ <area id="version4" coords="5 70"/>
+ <area id="version5" coords="6 70"/>
+ </areaspec>
+ <programlisting><![CDATA[<version
+ column="version_column"
+ name="propertyName"
+ type="typename"
+ access="field|property|ClassName"
+ unsaved-value="null|negative|undefined"
+ node="element-name|@attribute-name|element/@attribute|."
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="version1">
+ <para>
+ <literal>column</literal> (opcional - por defecto al nombre de la propiedad): El nombre
+ de la columna que tiene el número de versión.
+ </para>
+ </callout>
+ <callout arearefs="version2">
+ <para>
+ <literal>name</literal>: El nombre de una propiedad de la clase persistente.
+ </para>
+ </callout>
+ <callout arearefs="version3">
+ <para>
+ <literal>type</literal> (opcional - por defecto a <literal>integer</literal>):
+ El tipo del nú.mero de vesión.
+ </para>
+ </callout>
+ <callout arearefs="version4">
+ <para>
+ <literal>access</literal> (opcional - por defecto a <literal>property</literal>): La
+ estrategia que Hibernate debe usar para acceder al valor de la propiedad.
+ </para>
+ </callout>
+ <callout arearefs="version5">
+ <para>
+ <literal>unsaved-value</literal> (opcional - por defecto a <literal>undefined</literal>):
+ Un valor de la propiedad de versión que indica que una instancia está
+ recién instanciada (sin guardar), distinguiéndola de instancias
+ separadas que fueran guardadas o cargadas en una sesión previa.
+ (<literal>undefined</literal> especifica que debe usarse el valor de la
+ propiedad identificadora.)
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Los números de versión deben ser de tipo <literal>long</literal>,
+ <literal>integer</literal>, <literal>short</literal>, <literal>timestamp</literal> o
+ <literal>calendar</literal> de Hibernate.
+ </para>
+
+ <para>
+ Una propiedad de versión o timestamp nunca debe ser nula para una instancia
+ separada, de modo que Hibernate detectará cualquier instancia con una versión
+ o timestamp nulo como transitoria, sin importar qué otras estrategias
+ <literal>unsaved-value</literal> se hayan especificado.
+ <emphasis>Declarar una propiedad de versón o timestamp nulable es una forma
+ fácil de evitar cualquier problema con la re-unión transitiva en Hibernate,
+ especialmente útil para que usa identificadores asignados o claves compuestas!</emphasis>
+ </para>
+ </sect2>
+
+ <sect2 id="mapping-declaration-timestamp">
+ <title>timestamp (opcional)</title>
+
+ <para>
+ El elemento opcional <literal><timestamp></literal> indica que la tabla contiene
+ datos con sellos de tiempo. Esto esta concebido como una alternativa al versionado.
+ Los timestamps (sellos de tiempo) son por su naturaleza una implementación menos
+ segura de bloqueo optimista. Sin embrago, a veces la aplicación puede usar los
+ timestamps en otras formas.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="timestamp1" coords="2 70"/>
+ <area id="timestamp2" coords="3 70" />
+ <area id="timestamp3" coords="4 70" />
+ <area id="timestamp4" coords="5 70" />
+ </areaspec>
+ <programlisting><![CDATA[<timestamp
+ column="timestamp_column"
+ name="propertyName"
+ access="field|property|ClassName"
+ unsaved-value="null|undefined"
+ node="element-name|@attribute-name|element/@attribute|."
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="timestamp1">
+ <para>
+ <literal>column</literal> (opcional - por defecto al nombre de la propiedad): El nombre
+ de una columna que tiene el timestamp.
+ </para>
+ </callout>
+ <callout arearefs="timestamp2">
+ <para>
+ <literal>name</literal>: El nombre de una propiedad del estilo JavaBeans de tipo
+ Java <literal>Date</literal> o <literal>Timestamp</literal> de la clase persistente.
+ </para>
+ </callout>
+ <callout arearefs="timestamp3">
+ <para>
+ <literal>access</literal> (opcional - por defecto a <literal>property</literal>): La
+ estrategia que Hibernate debe usar para acceder al valor de la propiedad.
+ </para>
+ </callout>
+ <callout arearefs="timestamp4">
+ <para>
+ <literal>unsaved-value</literal> (opcional - por defecto a <literal>null</literal>):
+ Un valor de propiedad de versión que indica que una instancia está
+ recién instanciada (sin guardar), distinguiéndola de instancias separadas
+ que hayan sido guardadas o cargadas en una sesión previa.
+ (<literal>undefined</literal> especifica que debe usarse el valor de la propiedad
+ identificadora.)
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Note that <literal><timestamp></literal> is equivalent to
+ <literal><version type="timestamp"></literal>.
+ </para>
+ </sect2>
+
+
+ <sect2 id="mapping-declaration-property" revision="2">
+ <title>property</title>
+
+ <para>
+ El elemento <literal><property></literal> declara una propiedad persistente estilo
+ JavaBean de la clase.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="property1" coords="2 70"/>
+ <area id="property2" coords="3 70"/>
+ <area id="property3" coords="4 70"/>
+ <areaset id="property4-5" coords="">
+ <area id="property4" coords='5 70'/>
+ <area id="property5" coords='6 70'/>
+ </areaset>
+ <area id="property6" coords="7 70"/>
+ <area id="property7" coords="8 70"/>
+ <area id="property8" coords="9 70"/>
+ <area id="property9" coords="10 70"/>
+ <area id="property10" coords="11 70"/>
+ <area id="property11" coords="12 70"/>
+ </areaspec>
+ <programlisting><![CDATA[<property
+ name="propertyName"
+ column="column_name"
+ type="typename"
+ update="true|false"
+ insert="true|false"
+ formula="arbitrary SQL expression"
+ access="field|property|ClassName"
+ lazy="true|false"
+ unique="true|false"
+ not-null="true|false"
+ optimistic-lock="true|false"
+ node="element-name|@attribute-name|element/@attribute|."
+ index="index_name"
+ unique_key="unique_key_id"
+ length="L"
+ precision="P"
+ scale="S"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="property1">
+ <para>
+ <literal>name</literal>: el nombre de la propiedad, con la letra inicial
+ en minúsculas.
+ </para>
+ </callout>
+ <callout arearefs="property2">
+ <para>
+ <literal>column</literal> (opcional - por defecto al nombre de la propiedad): el nombre
+ de la columna de tabla de base de datos mapeada. Esto puede también ser especificado
+ con elemento(s) <literal><column></literal> anidado(s).
+ </para>
+ </callout>
+ <callout arearefs="property3">
+ <para>
+ <literal>type</literal> (opcional): un nombre que indica el nobre Hibernate.
+ </para>
+ </callout>
+ <callout arearefs="property4-5">
+ <para>
+ <literal>update, insert</literal> (opcional - por defecto a <literal>true</literal>) :
+ especifica que las columnas mapeadas deben ser incluídas en las sentencias SQL
+ <literal>UPDATE</literal> y/o <literal>INSERT</literal> . Especificando ambas a
+ <literal>false</literal> permite una propiedad "derivada" cuyo valor es inicializado desde
+ alguna otra propiedad que mapee a la misma columna (o columnas) o por un disparador u otra
+ aplicación.
+ </para>
+ </callout>
+ <callout arearefs="property6">
+ <para>
+ <literal>formula</literal> (opcional): una expresión SQL que define el valor
+ para una propiedad <emphasis>computada</emphasis>. Las propiedades computadas no tienen
+ una columna mapeada propia.
+ </para>
+ </callout>
+ <callout arearefs="property7">
+ <para>
+ <literal>access</literal> (opcional - por defecto a <literal>property</literal>): La
+ estrategia que Hibernate debe usar para acceder al valor de la propiedad.
+ </para>
+ </callout>
+ <callout arearefs="property8">
+ <para>
+ <literal>lazy</literal> (opcional - por defecto a <literal>false</literal>): Especifica
+ que esta propiedad debe ser traída perezosamente cuando la variable de instancia
+ sea accedida por primera vez (requiere instrumentación en tiempo de compilación).
+ </para>
+ </callout>
+ <callout arearefs="property9">
+ <para>
+ <literal>unique</literal> (opcional): Habilita la generació DDL de una restricción
+ de unicidad para las columnas. Además, permite que ésta sea un blanco objetivo de
+ una <literal>property-ref</literal>.
+ </para>
+ </callout>
+ <callout arearefs="property10">
+ <para>
+ <literal>not-null</literal> (opcional): Habilita la generació DDL de una restricción
+ de nulabilidad para las columnas.
+ </para>
+ </callout>
+ <callout arearefs="property11">
+ <para>
+ <literal>optimistic-lock</literal> (opcional - por defecto a <literal>true</literal>):
+ Especifica que las actualizaciones a esta propiedad requieran o no de la obtención
+ de un bloqueo optimista. En otras palabras, determina si debe ocurrir un incremento de versión
+ cuando la propiedad este sucia (desactualizada).
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ <emphasis>typename</emphasis> puede ser:
+ </para>
+
+ <orderedlist spacing="compact">
+ <listitem>
+ <para>
+ El nombre de un tipo básico Hibernate (por ejemplo, <literal>integer, string, character,
+ date, timestamp, float, binary, serializable, object, blob</literal>).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ El nombre de una clase Java de tipo básico (por ejemplo, <literal>int, float,
+ char, java.lang.String, java.util.Date, java.lang.Integer, java.sql.Clob</literal>).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ El nombre de una clase Java serializable.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ El nombre de un tipo personalizado (por ejemplo, <literal>com.illflow.type.MyCustomType</literal>).
+ </para>
+ </listitem>
+ </orderedlist>
+
+ <para>
+ Si no especificas un tipo, Hibernate usará reflección sobre la
+ propiedad mencionada para deducir el tipo Hibernate correcto. Hibernate intentará
+ interpretar el nombre de la clase de retorno del getter de la propiedad usando las reglas
+ 2, 3 y 4 en ese orden. Sin embargo, esto no siempre suficiente. En ciertos casos, necesitarás
+ aún el atributo <literal>type</literal>. (Por ejemplo, para distinguir entre
+ <literal>Hibernate.DATE</literal> y <literal>Hibernate.TIMESTAMP</literal>,
+ o especificar un tipo personalizado.)
+ </para>
+
+ <para>
+ El atributo <literal>access</literal> te deja controlar cómo Hibernate
+ accederá a la propiedad en tiempo de ejecución. Por defecto, Hibernate
+ llamará al par de getter/setter de la propiedad. Si especificas
+ <literal>access="field"</literal>, Hibernate se saltará el par get/set y
+ accederá al campo directamente usando reflección. Puedes especificar tu
+ propia estrategia de acceso a la propiedad mencionando una clase que implemente
+ la interface <literal>org.hibernate.property.PropertyAccessor</literal>.
+ </para>
+
+ <para>
+ Una aspecto especialmente poderoso son las propiedades derivadas. Estas propiedades
+ son por definición de sólo lectura, el valor de la propiedad es computado
+ en tiempo de carga. Tu declaras la computación como una expresión SQL,
+ y ésta se traduce a cláusula de subconsulta <literal>SELECT</literal>
+ en la consulta SQL que cargue una instancia:
+ </para>
+
+ <programlisting><![CDATA[
+<property name="totalPrice"
+ formula="( SELECT SUM (li.quantity*p.price) FROM LineItem li, Product p
+ WHERE li.productId = p.productId
+ AND li.customerId = customerId
+ AND li.orderNumber = orderNumber )"/>]]></programlisting>
+
+ <para>
+ Observa que puedes referenciar la propia tabla de las entidades sin declarar un alias
+ o una columna particular (<literal>customerId</literal> en el ejemplo dado). Observa
+ además que puedes usar el elemento anidado de mapeo <literal><formula></literal>
+ si no te gusta usar el atributo.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-manytoone" revision="3">
+ <title>many-to-one</title>
+
+ <para>
+ Una asociación ordinaria a otra clase persistente se declara usando
+ el elemento <literal>many-to-one</literal>. El modelo relacional es una
+ asociación muchos-a-uno: una clave foránea en una tabla está
+ referenciando la columna (o columnas) de la clave primaria de la tabla objetivo.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="manytoone1" coords="2 70"/>
+ <area id="manytoone2" coords="3 70"/>
+ <area id="manytoone3" coords="4 70"/>
+ <area id="manytoone4" coords="5 70"/>
+ <area id="manytoone5" coords="6 70"/>
+ <areaset id="manytoone6-7" coords="">
+ <area id="manytoone6" coords='7 70'/>
+ <area id="manytoone7" coords='8 70'/>
+ </areaset>
+ <area id="manytoone8" coords="9 70"/>
+ <area id="manytoone9" coords="10 70"/>
+ <area id="manytoone10" coords="11 70"/>
+ <area id="manytoone11" coords="12 70"/>
+ <area id="manytoone12" coords="13 70"/>
+ <area id="manytoone13" coords="14 70"/>
+ <area id="manytoone14" coords="15 70"/>
+ <area id="manytoone15" coords="16 70"/>
+ <area id="manytoone16" coords="17 70"/>
+ </areaspec>
+ <programlisting><![CDATA[<many-to-one
+ name="propertyName"
+ column="column_name"
+ class="ClassName"
+ cascade="cascade_style"
+ fetch="join|select"
+ update="true|false"
+ insert="true|false"
+ property-ref="propertyNameFromAssociatedClass"
+ access="field|property|ClassName"
+ unique="true|false"
+ not-null="true|false"
+ optimistic-lock="true|false"
+ lazy="true|proxy|false"
+ not-found="ignore|exception"
+ entity-name="EntityName"
+ formula="cualquier expresión SQL"
+ node="element-name|@attribute-name|element/@attribute|."
+ embed-xml="true|false"
+ index="index_name"
+ unique_key="unique_key_id"
+ foreign-key="foreign_key_name"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="manytoone1">
+ <para>
+ <literal>name</literal>: El nombre de la propiedad.
+ </para>
+ </callout>
+ <callout arearefs="manytoone2">
+ <para>
+ <literal>column</literal> (opcional): El nombre de la columna clave foránea.
+ También puede ser especificado por uno o varios elementos anidados
+ <literal><column></literal>.
+ </para>
+ </callout>
+ <callout arearefs="manytoone3">
+ <para>
+ <literal>class</literal> (opcional - por defecto al tipo de la propiedad
+ determinado por reflección): El nombre de la clase asociada.
+ </para>
+ </callout>
+ <callout arearefs="manytoone4">
+ <para>
+ <literal>cascade</literal> (opcional): Especifica qué operaciones deben
+ ir en cascada desde el objeto padre al objeto asociado
+ </para>
+ </callout>
+ <callout arearefs="manytoone5">
+ <para>
+ <literal>fetch</literal> (opcional - por defecto a 1<literal>select</literal>):
+ Escoge entre recuperación outer-join o por selección secuencial.
+ </para>
+ </callout>
+ <callout arearefs="manytoone6-7">
+ <para>
+ <literal>update, insert</literal> (opcional - por defecto a <literal>true</literal>)
+ especifica que las columnas mapeadas deben ser incluídas en las sentencias SQL
+ <literal>UPDATE</literal> y/o <literal>INSERT</literal>. Establecer ambas a
+ <literal>false</literal> permite una asociación puramente "derivada" cuyo
+ valor es inicializado desde alguna otra propiedad que mapea a las misma columna (o columnas),
+ o por un disparador, o por otra aplicación.
+ </para>
+ </callout>
+ <callout arearefs="manytoone8">
+ <para>
+ <literal>property-ref</literal>: (opcional) El nombre de la propiedad de la clase
+ asociada que está unida a la clave foránea. Si no se especifica, se usa
+ la clave primaria de la clase asociada.
+ </para>
+ </callout>
+ <callout arearefs="manytoone9">
+ <para>
+ <literal>access</literal> (opcional - por defecto a <literal>property</literal>): La
+ estrategia que Hibernate debe usar para acceder al valor de la propiedad.
+ </para>
+ </callout>
+ <callout arearefs="manytoone10">
+ <para>
+ <literal>unique</literal> (opcional): Habilita la generación DDL de una
+ restricción de unicidad para la columna de clave foránea. Además,
+ permite que ésta sea el objetivo de una <literal>property-ref</literal>.
+ Esto hace efectivamente la multiplicidad de la asociación uno a uno.
+ </para>
+ </callout>
+ <callout arearefs="manytoone11">
+ <para>
+ <literal>not-null</literal> (opcional): Habilita la generación DDL de una
+ restricción de nulabilidad para las columnas de clave foránea.
+ </para>
+ </callout>
+ <callout arearefs="manytoone12">
+ <para>
+ <literal>optimistic-lock</literal> (opcional - por defecto a <literal>true</literal>):
+ Especifica que las actualizaciones a esta propiedad requieran o no la obtención
+ del bloqueo optimista. En otras palabras, determina si debe darse un incremento de versión
+ cuando esta propiedad esté desactualizada.
+ </para>
+ </callout>
+ <callout arearefs="manytoone13">
+ <para>
+ <literal>lazy</literal> (opcional - por defecto a <literal>proxy</literal>):
+ Por defecto, las asociaciones de punto único van con proxies.
+ <literal>lazy="true"</literal> especifica que esta propiedad debe ser
+ traída perezosamente cuando la variable de instancia sea accedida por primera
+ vez (requiere instrumentación del bytecode en tiempo de compilación).
+ <literal>lazy="false"</literal> especifica que la asociación siempre será
+ recuperada tempranamente.
+ </para>
+ </callout>
+ <callout arearefs="manytoone14">
+ <para>
+ <literal>not-found</literal> (opcional - por defecto a <literal>exception</literal>):
+ Especifica cómo deben manejarse las claves foráneas que referencien
+ filas inexistentes: <literal>ignore</literal> tratará una fila perdida como
+ una asociación nula.
+ </para>
+ </callout>
+ <callout arearefs="manytoone15">
+ <para>
+ <literal>entity-name</literal> (opcional): El nombre de entidad de la clase
+ asociada.
+ </para>
+ </callout>
+ <callout arearefs="manytoone16">
+ <para>
+ <literal>formula</literal> (opcional): una expresión SQL que define el valor
+ para una clave foránea <emphasis>computada</emphasis>.
+ </para>
+ </callout>
+
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Establecer el valor del atributo <literal>cascade</literal> a cualquier valor
+ significativo distinto de <literal>none</literal> propagará ciertas
+ operaciones al objeto asociado. Los valores significativos son los nombres de las
+ operaciones básicas de Hibernate, <literal>persist, merge, delete, save-update,
+ evict, replicate, lock, refresh</literal>, así como los valores especiales
+ <literal>delete-orphan</literal> y <literal>all</literal> y combinaciones de operaciones
+ separadas por coma, por ejemplo, <literal>cascade="persist,merge,evict"</literal> o
+ <literal>cascade="all,delete-orphan"</literal>. Para una explicación completa,
+ ver <xref linkend="objectstate-transitive"/>.
+ </para>
+
+ <para>
+ Una declaración típica <literal>muchos-a-uno</literal> se parece a esto:
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="product" class="Product" column="PRODUCT_ID"/>]]></programlisting>
+
+ <para>
+ El atributo <literal>property-ref</literal> debe ser usado solamente para el mapeo
+ de datos heredados donde una clave foránea referencia una clave única de
+ la tabla asociada, distinta de la clave primaria. Este es un modelo relacional feo.
+ Por ejemplo, supón que la clase <literal>Product</literal> tuviera un número
+ único serial que no es la clave primaria. (El atributo <literal>unique</literal>
+ controla la generación de DDL con la herramienta SchemaExport.)
+ </para>
+
+ <programlisting><![CDATA[<property name="serialNumber" unique="true" type="string" column="SERIAL_NUMBER"/>]]></programlisting>
+
+ <para>
+ Entonces el mapeo para <literal>OrderItem</literal> debería usar:
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="product" property-ref="serialNumber" column="PRODUCT_SERIAL_NUMBER"/>]]></programlisting>
+
+ <para>
+ Sin embargo, esto no esta ciertamente alentado.
+ </para>
+
+ <para>
+ Si la clave única referenciada abarca múltiples propiedades de la entidad asociada,
+ debes mapear las propiedades dentro de un elemento <literal><properties></literal>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-onetoone" revision="2">
+ <title>one-to-one</title>
+
+ <para>
+ Una asociación uno-a-uno a otra clase persistente se declara usando
+ un elemento <literal>one-to-one</literal>.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="onetoone1" coords="2 70"/>
+ <area id="onetoone2" coords="3 70"/>
+ <area id="onetoone3" coords="4 70"/>
+ <area id="onetoone4" coords="5 70"/>
+ <area id="onetoone5" coords="6 70"/>
+ <area id="onetoone6" coords="7 70"/>
+ <area id="onetoone7" coords="8 70"/>
+ <area id="onetoone8" coords="9 70"/>
+ <area id="onetoone9" coords="10 70"/>
+ <area id="onetoone10" coords="11 70"/>
+ </areaspec>
+ <programlisting><![CDATA[<one-to-one
+ name="propertyName"
+ class="ClassName"
+ cascade="cascade_style"
+ constrained="true|false"
+ fetch="join|select"
+ property-ref="propertyNameFromAssociatedClass"
+ access="field|property|ClassName"
+ formula="cualquier expresión SQL"
+ lazy="true|proxy|false"
+ entity-name="EntityName"
+ node="element-name|@attribute-name|element/@attribute|."
+ embed-xml="true|false"
+ foreign-key="foreign_key_name"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="onetoone1">
+ <para>
+ <literal>name</literal>: El nombre de la propiedad.
+ </para>
+ </callout>
+ <callout arearefs="onetoone2">
+ <para>
+ <literal>class</literal> (opcional - por defecto al tipo de la propiedad
+ determinado por reflección): El nombre de la clase asociada.
+ </para>
+ </callout>
+ <callout arearefs="onetoone3">
+ <para>
+ <literal>cascade</literal> (opcional) especifica qué operaciones deben
+ ir en cascada desde el objeto padre al objeto asociado.
+ </para>
+ </callout>
+ <callout arearefs="onetoone4">
+ <para>
+ <literal>constrained</literal> (opcional) especifica que una restricción
+ de clave foránea de la tabla mapeada referencia a la tabla de la clase
+ asociada. Esta opción afecta el orden en que van en cascada
+ <literal>save()</literal> y <literal>delete()</literal>, y determina cuándo
+ la asociación pueden ser virtualizados por proxies (es también usado por
+ la herramienta de exportación de esquemas).
+ </para>
+ </callout>
+ <callout arearefs="onetoone5">
+ <para>
+ <literal>fetch</literal> (opcional - por defecto <literal>select</literal>):
+ Elige entre recuperación outer-join o recuperación por consulta secuencial.
+ </para>
+ </callout>
+ <callout arearefs="onetoone6">
+ <para>
+ <literal>property-ref</literal>: (opcional) El nombre de una propiedad de la clase
+ asociada que esté unida a la clave primaria de esta clase. Si no se especifica,
+ se usa la clave primaria de la clase asociada.
+ </para>
+ </callout>
+ <callout arearefs="onetoone7">
+ <para>
+ <literal>access</literal> (opcional - por defecto a <literal>property</literal>): La
+ estrategia que Hibernate debe usar para acceder al valor de la propiedad.
+ </para>
+ </callout>
+ <callout arearefs="onetoone8">
+ <para>
+ <literal>formula</literal> (opcional): Casi todas las asociaciones uno-a-uno mapean
+ a la clave primaria de la entidad propietaria. En el raro caso en que este no sea el caso,
+ puedes especificar alguna otra columna, o columnas, o expresión para unir usando una
+ fórmula SQL. (Para un ejemplo ver <literal>org.hibernate.test.onetooneformula</literal>).
+ </para>
+ </callout>
+ <callout arearefs="onetoone9">
+ <para>
+ <literal>lazy</literal> (opcional - por defecto a <literal>proxy</literal>):
+ Por defecto, las asociaciones de punto único van con proxies.
+ <literal>lazy="true"</literal> especifica que esta propiedad debe ser
+ traída perezosamente cuando la variable de instancia sea accedida por primera
+ vez (requiere instrumentación del bytecode en tiempo de compilación).
+ <literal>lazy="false"</literal> especifica que la asociación siempre será
+ recuperada tempranamente. <emphasis>Observa que si <literal>constrained="false"</literal>,
+ la aplicación de proxies es imposible e Hibernate traerá temprano la
+ asociación!</emphasis>
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Hay dos variedades de asociaciones uno-a-uno:
+ </para>
+ <itemizedlist>
+ <listitem><para>
+ asociaciones de clave primaria
+ </para></listitem>
+ <listitem><para>
+ asociaciones de clave foráneas única
+ </para></listitem>
+ </itemizedlist>
+
+ <para>
+ Las asociaciones de clave primaria no necesitan una columna de tabla extra; si dos filas
+ están relacionadas por la asociación entonces las dos filas de tablas comparten
+ el mismo valor de clave primaria. Por lo tanto, si quieres que dos objetos estén relacionados
+ por una asociación de clave primaria, debes asegurarte que se les asigne el mismo valor de
+ identificador!
+ </para>
+
+ <para>
+ Para una asociación de clave primaria, añade los siguientes mapeos a
+ <literal>Employee</literal> y <literal>Person</literal>, respectivamente.
+ </para>
+
+ <programlisting><![CDATA[<one-to-one name="person" class="Person"/>]]></programlisting>
+ <programlisting><![CDATA[<one-to-one name="employee" class="Employee" constrained="true"/>]]></programlisting>
+
+ <para>
+ Ahora debemos asegurarnos que las claves primarias de las filas relacionadas en las tablas
+ PERSON y EMPLOYEE sean iguales. Usamos una estrategia especial de generación de identificador
+ de Hibernate llamada <literal>foreign</literal>:
+ </para>
+
+ <programlisting><![CDATA[<class name="person" table="PERSON">
+ <id name="id" column="PERSON_ID">
+ <generator class="foreign">
+ <param name="property">employee</param>
+ </generator>
+ </id>
+ ...
+ <one-to-one name="employee"
+ class="Employee"
+ constrained="true"/>
+</class>]]></programlisting>
+
+ <para>
+ A una instancia recién salvada de <literal>Person</literal> se le asigna entonces
+ el mismo valor de clave primaria con que la instancia <literal>Employee</literal>
+ referida por la propiedad <literal>employee</literal> de esta <literal>Person</literal>.
+ </para>
+
+ <para>
+ Alternativamente, una clave foránea con una restricción de unicidad, desde
+ <literal>Employee</literal> a <literal>Person</literal>, puede ser expresada como:
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="person" class="Person" column="PERSON_ID" unique="true"/>]]></programlisting>
+
+ <para>
+ Y esta asociación puede hacerse bidireccional agregando lo siguiente al mapeo de
+ <literal>Person</literal> :
+ </para>
+
+ <programlisting><![CDATA[<one-to-one name="employee" class="Employee" property-ref="person"/>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-naturalid">
+ <title>natural-id</title>
+
+ <programlisting><![CDATA[<natural-id mutable="true|false"/>
+ <property ... />
+ <many-to-one ... />
+ ......
+</natural-id>]]></programlisting>
+
+ <para>
+ Aunque recomendamos el uso de claves delegadas como claves primarias, todavía debes
+ intentar identificar claves naturales para todas las entidades. Una clave natural es una
+ propiedad o combinación de propiedades que es única y no nula. Si además
+ es inmutable, mejor aún. Mapea las propiedades de la clave natural dentro del elemento
+ <literal><natural-id></literal>. Hibernate generará las restricciones de clave
+ única y nulabilidad necesarias, y tu mapeo será más auto-documentado.
+ </para>
+
+ <para>
+ Recomendamos fuertemente que implementes <literal>equals()</literal> y
+ <literal>hashCode()</literal> para comparar las propiedades de clave natural
+ de la entidad.
+ </para>
+
+ <para>
+ Este mapeo no está concebido para usar con entidades con claves
+ primarias naturales.
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>mutable</literal> (opcional, por defecto a <literal>false</literal>):
+ Por defecto, se asume que las propiedades de identificadores naturales son
+ inmutables (constantes).
+ </para>
+ </listitem>
+ </itemizedlist>
+ </sect2>
+
+
+
+ <sect2 id="mapping-declaration-component" revision="2">
+ <title>component, dynamic-component</title>
+
+ <para>
+ El elemento <literal><component></literal> mapea propiedades de un objeto
+ hijo a columnas de la tabla de la clase padre. Los componentes pueden a su vez
+ declarar sus propias propiedades, componentes o colecciones. Ver debajo "Componentes".
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="component1" coords="2 45"/>
+ <area id="component2" coords="3 45"/>
+ <area id="component3" coords="4 45"/>
+ <area id="component4" coords="5 45"/>
+ <area id="component5" coords="6 45"/>
+ <area id="component6" coords="7 45"/>
+ <area id="component7" coords="8 45"/>
+ <area id="component8" coords="9 45"/>
+ </areaspec>
+ <programlisting><![CDATA[<component
+ name="propertyName"
+ class="className"
+ insert="true|false"
+ update="true|false"
+ access="field|property|ClassName"
+ lazy="true|false"
+ optimistic-lock="true|false"
+ unique="true|false"
+ node="element-name|."
+>
+
+ <property ...../>
+ <many-to-one .... />
+ ........
+</component>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="component1">
+ <para>
+ <literal>name</literal>: El nombre de la propiedad.
+ </para>
+ </callout>
+ <callout arearefs="component2">
+ <para>
+ <literal>class</literal> (opcional - por defecto al tipo de la propiedad
+ determinado por reflección): El nombre de la clase del componente (hijo).
+ </para>
+ </callout>
+ <callout arearefs="component3">
+ <para>
+ <literal>insert</literal>: Aparecen las columnas mapeadas en
+ <literal>INSERT</literal>s SQL?
+ </para>
+ </callout>
+ <callout arearefs="component4">
+ <para>
+ <literal>update</literal>: Aparecen las columnas mapeadas en
+ <literal>UPDATE</literal>s SQL?
+ </para>
+ </callout>
+ <callout arearefs="component5">
+ <para>
+ <literal>access</literal> (opcional - por defecto a <literal>property</literal>): La
+ estrategia que Hibernate debe usar para acceder al valor de la propiedad.
+ </para>
+ </callout>
+ <callout arearefs="component6">
+ <para>
+ <literal>lazy</literal> (opcional - por defecto a <literal>false</literal>): Especifica
+ que este componente debe ser recuperado perezosamente cuando la variable de instancia
+ sea accedida por primera vez (requiere instrumentación de bytecode en tiempo de
+ compilación).
+ </para>
+ </callout>
+ <callout arearefs="component7">
+ <para>
+ <literal>optimistic-lock</literal> (opcional - por defecto a <literal>true</literal>):
+ Especifica si las actualizaciones de este componente requieren o no la
+ adquisición de un bloqueo optimista. En otras palabras, determina si
+ debe ocurrir un incremento de versión cuando esta propiedad está
+ desactualizada.
+ </para>
+ </callout>
+ <callout arearefs="component8">
+ <para>
+ <literal>unique</literal> (opcional - por defecto a <literal>false</literal>):
+ Especifica que existe una restricción de unicidad sobre todas las
+ columnas mapeadas del componente.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Las etiquetas hijas <literal><property></literal> mapean propiedades de la
+ clase hija columnas de la tabla.
+ </para>
+
+ <para>
+ El elemento <literal><component></literal> permite un subelemento
+ <literal><parent></literal> que mapea una propiedad de la clase del componente
+ como una referencia de regreso a la entidad contenedora.
+ </para>
+
+ <para>
+ El elemento <literal><dynamic-component></literal> permite que un
+ <literal>Map</literal> sea mapeado como un componente, donde los nombres de
+ las propiedades se corresponden a las claves del mapa, ver <xref linkend="components-dynamic"/>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-properties" revision="2">
+ <title>properties</title>
+
+ <para>
+ El elemento <literal><properties></literal> permite la definición de
+ un grupo de propiedades lógico con nombre de una clase. El uso más
+ importante de la contrucción es que permite que una combinación
+ de propiedades sea objetivo de una <literal>property-ref</literal>. Es también
+ una forma conveniente de definir una restricción de unicidad multicolumna.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="properties1" coords="2 45"/>
+ <area id="properties2" coords="3 45"/>
+ <area id="properties3" coords="4 45"/>
+ <area id="properties4" coords="5 45"/>
+ <area id="properties5" coords="6 45"/>
+ </areaspec>
+ <programlisting><![CDATA[<properties
+ name="logicalName"
+ insert="true|false"
+ update="true|false"
+ optimistic-lock="true|false"
+ unique="true|false"
+>
+
+ <property ...../>
+ <many-to-one .... />
+ ........
+</properties>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="properties1">
+ <para>
+ <literal>name</literal>: El nombre lógico del agrupamiento -
+ <emphasis>no</emphasis> un nombre de propiedad real.
+ </para>
+ </callout>
+ <callout arearefs="properties2">
+ <para>
+ <literal>insert</literal>: Aparecen las columnas mapeadas en
+ <literal>INSERT</literal>s SQL?
+ </para>
+ </callout>
+ <callout arearefs="properties3">
+ <para>
+ <literal>update</literal>: Aparecen las columnas mapeadas en
+ <literal>UPDATE</literal>s SQL?
+ </para>
+ </callout>
+ <callout arearefs="properties4">
+ <para>
+ <literal>optimistic-lock</literal> (opcional - por defecto a <literal>true</literal>):
+ Especifica si las actualizaciones de estas propiedades requieren o no de la
+ adquisición de un bloqueo optimista. En otras palabras, determina si
+ debe ocurrir un incremento de versión cuando estas propiedades están
+ desactualizadas.
+ </para>
+ </callout>
+ <callout arearefs="properties5">
+ <para>
+ <literal>unique</literal> (opcional - por defecto a <literal>false</literal>):
+ Especifica que existe una restricción de unicidad sobre todas las
+ columnas mapeadas del componente.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Por ejemplo, si tenemos el siguiente mapeo de <literal><properties></literal>:
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="personNumber"/>
+ ...
+ <properties name="name"
+ unique="true" update="false">
+ <property name="firstName"/>
+ <property name="initial"/>
+ <property name="lastName"/>
+ </properties>
+</class>]]></programlisting>
+
+ <para>
+ Entonces puede que tengamos alguna asociación de datos heredados que se refiera
+ a esta clave única de la tabla de <literal>Person</literal>, en vez de la clave
+ primaria:
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="person"
+ class="Person" property-ref="name">
+ <column name="firstName"/>
+ <column name="initial"/>
+ <column name="lastName"/>
+</many-to-one>]]></programlisting>
+
+ <para>
+ No recomendamos el uso de este tipo de cosas fuera del contexto del mapeo de
+ datos heredados.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-subclass" revision="3">
+ <title>subclass</title>
+
+ <para>
+ Finalmente, la persistencia polimórfica requiere la declaración
+ de la clase persistente raíz. Para la estrategia de mapeo
+ tabla-por-jerarquía-de-clases, se usa la declaración de
+ <literal><subclass></literal>.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="subclass1" coords="2 55"/>
+ <area id="subclass2" coords="3 55"/>
+ <area id="subclass3" coords="4 55"/>
+ <area id="subclass4" coords="5 55"/>
+ </areaspec>
+ <programlisting><![CDATA[<subclass
+ name="ClassName"
+ discriminator-value="discriminator_value"
+ proxy="ProxyInterface"
+ lazy="true|false"
+ dynamic-update="true|false"
+ dynamic-insert="true|false"
+ entity-name="EntityName"
+ node="element-name">
+
+ <property .... />
+ .....
+</subclass>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="subclass1">
+ <para>
+ <literal>name</literal>: El nombre de clase cualificado completamente
+ de la subclase.
+ </para>
+ </callout>
+ <callout arearefs="subclass2">
+ <para>
+ <literal>discriminator-value</literal> (opcional - por defecto al nombre de la clase):
+ Un valor que distingue a subclases individuales.
+ </para>
+ </callout>
+ <callout arearefs="subclass3">
+ <para>
+ <literal>proxy</literal> (opcional): Especifica una clase o interface a usar para
+ proxies de inicialización perezosa.
+ </para>
+ </callout>
+ <callout arearefs="subclass4">
+ <para>
+ <literal>lazy</literal> (opcional, por defecto a <literal>true</literal>):
+ Establecer <literal>lazy="false"</literal> deshabilita el uso de recuperación
+ perezosa.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Cada subclase debe declarar sus propias propiedades persistentes y subclases.
+ Se asume que las propiedades <literal><version></literal> y <literal><id></literal>
+ son heredadas de la clase raíz. Cada subclase en una jerarquía debe
+ definir un <literal>discriminator-value</literal> único. Si no se especifica ninguno,
+ se usa el nombre completamente cualificado de clase Java.
+ </para>
+
+ <para>
+ Es posible definir mapeos <literal>subclass</literal>, <literal>union-subclass</literal>,
+ y <literal>joined-subclass</literal> en documentos de mapeo separados, directamente debajo
+ de <literal>hibernate-mapping</literal>. Esto te permite extender una jerarquía de clases
+ con sólo agregar un nuevo fichero de mapeo. Debes especificar un atributo
+ <literal>extends</literal> en el mapeo de la subclase, mencionando una superclase previamente mapeada.
+ Nota: Previamente esta funcionalidad hacía importante el orden de los documentos de mapeo.
+ Desde Hibernate3, el orden de los ficheros de mapeo no importa cuando se usa la palabra reservada
+ extends. El orden dentro de un mismo fichero de mapeo todavía necesita ser definido como
+ superclases antes de subclases.
+ </para>
+
+ <programlisting><![CDATA[
+<hibernate-mapping>
+ <subclass name="DomesticCat" extends="Cat" discriminator-value="D">
+ <property name="name" type="string"/>
+ </subclass>
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Para información acerca de mapeos de herencia, ver <xref linkend="inheritance"/>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-joinedsubclass" revision="3">
+ <title>joined-subclass</title>
+
+ <para>
+ Alternativamente, cada subclase puede ser mapeada a su propia tabla
+ (estrategia de mapeo tabla-por-subclase). El estado heredado se recupera
+ uniendo con la tabla de la superclase.
+ Usamos el elemento <literal><joined-subclass></literal>.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="joinedsubclass1" coords="2 45"/>
+ <area id="joinedsubclass2" coords="3 45"/>
+ <area id="joinedsubclass3" coords="4 45"/>
+ <area id="joinedsubclass4" coords="5 45"/>
+ </areaspec>
+ <programlisting><![CDATA[<joined-subclass
+ name="ClassName"
+ table="tablename"
+ proxy="ProxyInterface"
+ lazy="true|false"
+ dynamic-update="true|false"
+ dynamic-insert="true|false"
+ schema="schema"
+ catalog="catalog"
+ extends="SuperclassName"
+ persister="ClassName"
+ subselect="SQL expression"
+ entity-name="EntityName"
+ node="element-name">
+
+ <key .... >
+
+ <property .... />
+ .....
+</joined-subclass>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="joinedsubclass1">
+ <para>
+ <literal>name</literal>: El nombre de clase completamente cualificado de
+ la subclase.
+ </para>
+ </callout>
+ <callout arearefs="joinedsubclass2">
+ <para>
+ <literal>table</literal>: El nombre de tabla de la subclase.
+ </para>
+ </callout>
+ <callout arearefs="joinedsubclass3">
+ <para>
+ <literal>proxy</literal> (opcional): Especifica una clase o interface a
+ usar para proxies de inicializacón perezosa.
+ </para>
+ </callout>
+ <callout arearefs="joinedsubclass4">
+ <para>
+ <literal>lazy</literal> (opcional, por defecto a <literal>true</literal>):
+ Establecer <literal>lazy="false"</literal> deshabilita el uso de recuperación
+ perezosa.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ No se requiere de una columna discriminadora para esta estrategia de mapeo. Cada subclase debe,
+ sin embargo, declarar una columna de tabla que tenga el identificador del objeto usando el
+ elemento <literal><key></literal>. El mapeo del comienzo del capítulo
+ debería ser reescrito como:
+ </para>
+
+ <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+ <class name="Cat" table="CATS">
+ <id name="id" column="uid" type="long">
+ <generator class="hilo"/>
+ </id>
+ <property name="birthdate" type="date"/>
+ <property name="color" not-null="true"/>
+ <property name="sex" not-null="true"/>
+ <property name="weight"/>
+ <many-to-one name="mate"/>
+ <set name="kittens">
+ <key column="MOTHER"/>
+ <one-to-many class="Cat"/>
+ </set>
+ <joined-subclass name="DomesticCat" table="DOMESTIC_CATS">
+ <key column="CAT"/>
+ <property name="name" type="string"/>
+ </joined-subclass>
+ </class>
+
+ <class name="eg.Dog">
+ <!-- mapping for Dog could go here -->
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Para información acerca de mapeos de herencia, ver <xref linkend="inheritance"/>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-unionsubclass" revision="2">
+ <title>union-subclass</title>
+
+ <para>
+ Una tercera opción es mapear sólo las clases concretas de una
+ jerarquía de clases a tablas, (la estrategia tabla-por-clase-concreta)
+ donde cada tabla define todo el estado persistente de la clase, incluyendo el
+ estado heredado. En Hibernate, no es absolutamente necesario mapear dichas
+ jerarquías de herencia. Puedes simplemente mapear cada clase con una
+ declaración <literal><class></literal> separada. Sin embargo,
+ si deseas usar asociaciones polimórficas (por ejemplo, una asociación
+ a la superclase de tu jerarquía), debes usar el mapeo
+ <literal><union-subclass></literal>.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="unionsubclass1" coords="2 45"/>
+ <area id="unionsubclass2" coords="3 45"/>
+ <area id="unionsubclass3" coords="4 45"/>
+ <area id="unionsubclass4" coords="5 45"/>
+ </areaspec>
+ <programlisting><![CDATA[<union-subclass
+ name="ClassName"
+ table="tablename"
+ proxy="ProxyInterface"
+ lazy="true|false"
+ dynamic-update="true|false"
+ dynamic-insert="true|false"
+ schema="schema"
+ catalog="catalog"
+ extends="SuperclassName"
+ abstract="true|false"
+ persister="ClassName"
+ subselect="SQL expression"
+ entity-name="EntityName"
+ node="element-name">
+
+ <property .... />
+ .....
+</union-subclass>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="unionsubclass1">
+ <para>
+ <literal>name</literal>: El nombre de clase completamente cualificado de la subclase.
+ </para>
+ </callout>
+ <callout arearefs="unionsubclass2">
+ <para>
+ <literal>table</literal>: El nombre de tabla de la subclase.
+ </para>
+ </callout>
+ <callout arearefs="unionsubclass3">
+ <para>
+ <literal>proxy</literal> (optional): Especifica una clase o interface a
+ usar para proxies de inicializacón perezosa.
+ </para>
+ </callout>
+ <callout arearefs="unionsubclass4">
+ <para>
+ <literal>lazy</literal> (opcional, por defecto a <literal>true</literal>):
+ Establecer <literal>lazy="false"</literal> deshabilita el uso de recuperación
+ perezosa.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ No se requiere columna o columna clave discriminadora para esta estrategia de mapeo.
+ </para>
+
+ <para>
+ Para información acerca de mapeos de herencia, ver <xref linkend="inheritance"/>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-join" revision="3">
+ <title>join</title>
+
+ <para>
+ Usando el elemento <literal><join></literal>, es posible mapear
+ propiedades de una clase a varias tablas.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="join1" coords="2 50"/>
+ <area id="join2" coords="3 50"/>
+ <area id="join3" coords="4 50"/>
+ <area id="join4" coords="5 50"/>
+ <area id="join5" coords="6 50"/>
+ <area id="join6" coords="7 50"/>
+ </areaspec>
+ <programlisting><![CDATA[<join
+ table="tablename"
+ schema="owner"
+ catalog="catalog"
+ fetch="join|select"
+ inverse="true|false"
+ optional="true|false">
+
+ <key ... />
+
+ <property ... />
+ ...
+</join>]]></programlisting>
+
+ <calloutlist>
+ <callout arearefs="join1">
+ <para>
+ <literal>table</literal>: El nombre de la clase unida.
+ </para>
+ </callout>
+ <callout arearefs="join2">
+ <para>
+ <literal>schema</literal> (opcional): Sobrescribe el nombre de esquema
+ especificado por el elemento raíz <literal><hibernate-mapping></literal>.
+ </para>
+ </callout>
+ <callout arearefs="join3">
+ <para>
+ <literal>catalog</literal> (opcional): Sobrescribe el nombre de catálogo
+ especificado por el elemento raíz <literal><hibernate-mapping></literal>.
+ </para>
+ </callout>
+ <callout arearefs="join4">
+ <para>
+ <literal>fetch</literal> (opcional - por defecto a <literal>join</literal>):
+ Si se establece a <literal>join</literal>, por defecto, Hibernate usará
+ una unión interior (inner join) para recuperar un <literal><join></literal>
+ definido por una clase o sus superclases y una unión externa (outer join)
+ para un <literal><join></literal> definido por una subclase.
+ Si se establece a <literal>select</literal>, entonces Hibernate usará una
+ select secuencial para un <literal><join></literal> definido en una subclase,
+ que será publicada sólo si una fila resulta representar una instancia
+ de la subclase. Las uniones interiores todavía serán usados para
+ recuperar un <literal><join></literal> definido por la clase y sus superclases.
+ </para>
+ </callout>
+ <callout arearefs="join5">
+ <para>
+ <literal>inverse</literal> (opcional - por defecto a <literal>false</literal>):
+ De habilitarse, Hibernate no intentará insertar o actualizar las propiedades
+ definidas por esta unión.
+ </para>
+ </callout>
+ <callout arearefs="join6">
+ <para>
+ <literal>optional</literal> (opcional - por defecto a <literal>false</literal>):
+ De habilitarse, Hibernate insertará una fila sólo si las propiedades
+ definidas por esta unión son no nulas y siempre usará una unión
+ externa para recuperar las propiedades.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Por ejemplo, la información domiciliaria de una persona puede ser mapeada
+ a una tabla separada (preservando a la vez la semántica de tipo de valor para
+ todas las propiedades):
+ </para>
+
+ <programlisting><![CDATA[<class name="Person"
+ table="PERSON">
+
+ <id name="id" column="PERSON_ID">...</id>
+
+ <join table="ADDRESS">
+ <key column="ADDRESS_ID"/>
+ <property name="address"/>
+ <property name="zip"/>
+ <property name="country"/>
+ </join>
+ ...]]></programlisting>
+
+ <para>
+ Esta funcionalidad es a menudo solamente útil para modelos de datos
+ heredados; recomendamos menos tablas que clases un modelo de dominio más
+ granularizado. Sin embargo, es útil para cambiar entre estrategias de mapeo
+ de herencias en una misma jerarquía, como se explica luego.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-key">
+ <title>key</title>
+
+ <para>
+ Hasta ahora hemos visto el elemento <literal><key></literal> pocas veces.
+ Aparece en cualquier sitio en que el elemento padre de mapeo defina una unión
+ a una nueva tabla, y define la clave foránea en la tabla unida,
+ que referencia la clave primaria de la tabla original.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="key1" coords="2 50"/>
+ <area id="key2" coords="3 50"/>
+ <area id="key3" coords="4 50"/>
+ <area id="key4" coords="5 50"/>
+ <area id="key5" coords="6 50"/>
+ <area id="key6" coords="7 50"/>
+ </areaspec>
+ <programlisting><![CDATA[<key
+ column="columnname"
+ on-delete="noaction|cascade"
+ property-ref="propertyName"
+ not-null="true|false"
+ update="true|false"
+ unique="true|false"
+/>]]></programlisting>
+
+ <calloutlist>
+ <callout arearefs="key1">
+ <para>
+ <literal>column</literal> (opcional): El nombre de columna de la clave foránea.
+ Puede ser también especificado por elemento(s) anidado(s)
+ <literal><column></literal>.
+ </para>
+ </callout>
+ <callout arearefs="key2">
+ <para>
+ <literal>on-delete</literal> (opcional, por defecto a <literal>noaction</literal>):
+ Especifica si la restricción de clave foránea tiene el borrado en cascada
+ habilitado a nivel de base de datos.
+ </para>
+ </callout>
+ <callout arearefs="key3">
+ <para>
+ <literal>property-ref</literal> (opcional): Especifica que la clave foránea
+ referencia columnas que no son del la clave primaria de la tabla original.
+ (Provisto para datos heredados.)
+ </para>
+ </callout>
+ <callout arearefs="key4">
+ <para>
+ <literal>not-null</literal> (opcional): Especifica que las columnas de la clave
+ foránea son no nulables (esto está implicado si la clave foránea
+ es también parte de la clave primaria).
+ </para>
+ </callout>
+ <callout arearefs="key5">
+ <para>
+ <literal>update</literal> (opcional): Especifica que la clave foránea nunca
+ debe ser actualizada (esto está implicado si la clave foránea
+ es también parte de la clave primaria).
+ </para>
+ </callout>
+ <callout arearefs="key6">
+ <para>
+ <literal>unique</literal> (opcional): Especifica que la clave foránea
+ debe tener una restricción de unicidad (esto está implicado si
+ la clave foránea es también la clave primaria).
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Recomendamos que, para los sistemas en donde el rendimiento sea importante, todas las
+ claves deben ser definidas <literal>on-delete="cascade"</literal>, e Hibernate usará
+ una restricción <literal>ON CASCADE DELETE</literal> a nivel de base de datos,
+ en vez de muchas sentencias <literal>DELETE</literal> individuales. Ten en cuenta que
+ esta funcionalidad se salta la habitual estrategia de bloqueo optimista de Hibernate para
+ datos versionados.
+ </para>
+
+ <para>
+ Los atributos <literal>not-null</literal> y <literal>update</literal> son útiles
+ al mapear una asociación uno a muchos unidireccional. Si mapeas una uno a muchos
+ unidireccional a una clave foránea no nulable, <emphasis>debes</emphasis> declarar
+ la columna clave usando <literal><key not-null="true"></literal>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-column" revision="3">
+ <title>los elementos column y formula</title>
+ <para>
+ Cualquier elemento de mapeo que acepte un atributo <literal>column</literal> aceptará
+ alternativamente un subelemento <literal><column></literal>. De forma similar,
+ <literal><formula></literal> es una alternativa al atributo <literal>formula</literal>.
+ </para>
+
+ <programlisting><![CDATA[<column
+ name="column_name"
+ length="N"
+ precision="N"
+ scale="N"
+ not-null="true|false"
+ unique="true|false"
+ unique-key="multicolumn_unique_key_name"
+ index="index_name"
+ sql-type="sql_type_name"
+ check="SQL expression"/>]]></programlisting>
+
+ <programlisting><![CDATA[<formula>expresión SQL</formula>]]></programlisting>
+
+ <para>
+ Los atributos <literal>column</literal> y <literal>formula</literal> pueden
+ incluso ser combinados dentro del mismo mapeo de propiedad o asociación para
+ expresar, por ejemplo, condiciones de unión exóticas.
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="homeAddress" class="Address"
+ insert="false" update="false">
+ <column name="person_id" not-null="true" length="10"/>
+ <formula>'MAILING'</formula>
+</many-to-one>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="mapping-declaration-import">
+ <title>import</title>
+
+ <para>
+ Supón que tu aplicación tiene dos clases persistentes con el mismo nombre,
+ y no quieres especificar el nombre completamenta cualificado (paquete) en las consultas
+ Hibernate. Las clases pueden ser "importadas" explícitamente, en vez de confiar en
+ <literal>auto-import="true"</literal>. Puedes incluso importar clases e interfaces que
+ no estén mapeadas explícitamente.
+ </para>
+
+ <programlisting><![CDATA[<import class="java.lang.Object" rename="Universe"/>]]></programlisting>
+
+ <programlistingco>
+ <areaspec>
+ <area id="import1" coords="2 40"/>
+ <area id="import2" coords="3 40"/>
+ </areaspec>
+ <programlisting><![CDATA[<import
+ class="ClassName"
+ rename="ShortName"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="import1">
+ <para>
+ <literal>class</literal>: El nombre de clase completamente cualificado de
+ cualquier clase Java.
+ </para>
+ </callout>
+ <callout arearefs="import2">
+ <para>
+ <literal>rename</literal> (opcional - por defecto al nombre de clase sin cualificar):
+ Un nombre que será usado en el leguaje de consulta.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ </sect2>
+
+ <sect2 id="mapping-types-anymapping" revision="2">
+ <title>any</title>
+
+ <para>
+ Hay un tipo más de mapeo de propiedad. El elemento de mapeo <literal><any></literal>
+ define una asociacián polimórfica a clases desde múltiples tablas. Este tipo
+ de mapeo siempre requiere más de una columna. La primera columna contiene el tipo de la
+ entidad asociada. Las columnas restantes contienen el identificador. Es imposible especificar una
+ restricción de clave foránea para este tipo de asociación, por lo que
+ esto ciertamente no está concebido como la forma habitual de mapear asociaciones
+ (polimórficas). Sólo debes usar esto en casos muy especiales (por ejemplo,
+ trazas de auditoréa, datos de sesión de usuario, etc).
+ </para>
+
+ <para>
+ El atributo <literal>meta-type</literal> permite a la aplicación especificar un tipo
+ personalizado que mapee columnas de base de datos a clases persistentes que tengan propiedades
+ identificadoras del tipo especificado por <literal>id-type</literal>. Debes especificar el
+ mapeo de valores del meta-type a nombres de clase.
+ </para>
+
+ <programlisting><![CDATA[<any name="being" id-type="long" meta-type="string">
+ <meta-value value="TBL_ANIMAL" class="Animal"/>
+ <meta-value value="TBL_HUMAN" class="Human"/>
+ <meta-value value="TBL_ALIEN" class="Alien"/>
+ <column name="table_name"/>
+ <column name="id"/>
+</any>]]></programlisting>
+
+ <programlistingco>
+ <areaspec>
+ <area id="any1" coords="2 50"/>
+ <area id="any2" coords="3 50"/>
+ <area id="any3" coords="4 50"/>
+ <area id="any4" coords="5 50"/>
+ <area id="any5" coords="6 50"/>
+ <area id="any6" coords="7 50"/>
+ </areaspec>
+ <programlisting><![CDATA[<any
+ name="propertyName"
+ id-type="idtypename"
+ meta-type="metatypename"
+ cascade="cascade_style"
+ access="field|property|ClassName"
+ optimistic-lock="true|false"
+>
+ <meta-value ... />
+ <meta-value ... />
+ .....
+ <column .... />
+ <column .... />
+ .....
+</any>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="any1">
+ <para>
+ <literal>name</literal>: el nombre de la propiedad.
+ </para>
+ </callout>
+ <callout arearefs="any2">
+ <para>
+ <literal>id-type</literal>: el tipo del identificador.
+ </para>
+ </callout>
+ <callout arearefs="any3">
+ <para>
+ <literal>meta-type</literal> (opcional - por defecto a <literal>string</literal>):
+ Cualquier tipo que sea permitido para un mapeo de discriminador.
+ </para>
+ </callout>
+ <callout arearefs="any4">
+ <para>
+ <literal>cascade</literal> (opcional- por defecto a <literal>none</literal>):
+ el estilo de cascada.
+ </para>
+ </callout>
+ <callout arearefs="any5">
+ <para>
+ <literal>access</literal> (opcional - por defecto a <literal>property</literal>): La
+ estrategia que Hibernate debe usar para acceder al valor de la propiedad.
+ </para>
+ </callout>
+ <callout arearefs="any6">
+ <para>
+ <literal>optimistic-lock</literal> (opcional - por defecto a <literal>true</literal>):
+ Especifica si las actualizaciones de esta propiedad requieren o no de la
+ adquisición del bloqueo optimista. En otras palabras, determina si debe ocurrir
+ un incremento de versión cuando esta propiedad está desactualizada.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="mapping-types">
+ <title>Tipos de Hibernate</title>
+
+ <sect2 id="mapping-types-entitiesvalues" revision="1">
+ <title>Entidades y Valores</title>
+
+ <para>
+ Para entender el comportamiento de varios objetos a nivel de lenguaje Java
+ con respecto al servicio de persistencia, necesitamos clasificarlos en dos grupos:
+ </para>
+
+ <para>
+ Una <emphasis>entidad</emphasis> existe independientemente de cualquier otros
+ objetos que referencien a la entidad. Contrasta esto con el model habitual de Java
+ donde un objeto desreferenciado es recolectado como basura. Las entidades deben ser
+ salvadas y borradas explícitamente (excepto que las grabaciones y borrados
+ puedan ser <emphasis>tratados en cascada</emphasis> desde una entidad padre a sus hijos).
+ Esto es diferente al modelo de persistencia de objetos por alcance - y se corresponde
+ más de cerca a cómo los objetos de aplicación son usados
+ habitualmente en grandes sistemas. Las entidades soportan referencias circulares y
+ compartidas, que tambié pueden ser versionadas.
+ </para>
+
+ <para>
+ El estado persistente de una entidad consiste en referencias a otras entidades
+ e instancias de tipo <emphasis>valor</emphasis>. Los valores son primitivos,
+ colecciones (no lo que está dentro de la colección), componentes
+ y ciertos objetos inmutables. A diferencia de las entidades, los valores
+ (en particular las colecciones y los componentes) <emphasis>son</emphasis>
+ hechos persitentes y borrados por alcance. Como los objetos valor (y primitivos)
+ son persistidos y borrados junto a sus entidades contenedoras, no pueden ser
+ versionados independientemente. Los valores no tienen identidad independiente,
+ por los que no pueden ser compartidos por dos entidades o colleciones.
+ </para>
+
+ <para>
+ Hasta ahora, hemos estado usando el término "clase persistente"
+ para referirnos a entidades. Continuaremos haciéndolo. Hablando
+ estrictamente, sin embargo, no todas la clases con estado persistente
+ definidas por el usuario son entidades. Un <emphasis>componente</emphasis>
+ es una clase definida por el usuario con semántica de valor.
+ Una propiedad Java de tipo <literal>java.lang.String</literal> también
+ tiene semántica de valor. Dada esta definición, podemos decir
+ que todos los tipo (clases) provistos por el JDK tienen una semántica
+ de tipo valor en Java, mientras que los tipos definidos por el usuario
+ pueden ser mapeados con semántica de tipo valor o de entidad.
+ La desición corre por cuenta del desarrollador de la aplicación.
+ Un buen consejo para una clase entidad en un modelo de dominio son las referencias
+ compartidas a una sola instancia de esa clase, mientras que la composición
+ o agregación usualmente se traducen a un tipo de valor.
+ </para>
+
+ <para>
+ Volveremos a visitar ambos conceptos a lo largo de la documentación.
+ </para>
+
+ <para>
+ EL desafío es mapear el sistema de tipos de Java (y la definición
+ de entidades y tipos de valor de los desarrolladores) al sistema de tipos de
+ SQL/base de datos. EL puente entre ambos sistemas es provisto por Hibernate:
+ para las entidades usamos <literal><class></literal>,
+ <literal><subclass></literal>, etc. Para los tipos de valor usamos
+ <literal><property></literal>, <literal><component></literal>, etc,
+ usualmente con un atributo <literal>type</literal>. El valor de este atributo
+ es el nombre de un <emphasis>tipo de mapeo</emphasis> de Hibernate. Hibernate
+ provee de fábrica muchos mapeos (para tipos de valores del JDK
+ estándar). Puedes escribir tus propios mapeos de tipo, así como
+ implementar tus estrategias de conversión personalizadas, como veremos luego.
+ </para>
+
+ <para>
+ Todos los tipos prefabricados de Hibernate soportan semántica de nulos
+ excepto las colecciones.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-types-basictypes" revision="2">
+ <title>Tipos de valores básicos</title>
+
+ <para>
+ Los <emphasis>tipos de mapeo básicos</emphasis> prefabricados pueden ser
+ categorizado a grandes rasgos en:
+
+ <variablelist>
+ <varlistentry>
+ <term><literal>integer, long, short, float, double, character, byte,
+ boolean, yes_no, true_false</literal></term>
+ <listitem>
+ <para>
+ Mapeos de tipos primitivos de Java o clases de envoltura a
+ la tipos de columna SQL (especícifica del vendedor).
+ <literal>boolean, yes_no</literal> y <literal>true_false</literal>
+ son codificaciones alternativas a <literal>boolean</literal> de
+ Java o <literal>java.lang.Boolean</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>string</literal></term>
+ <listitem>
+ <para>
+ Un mapeo del tipo <literal>java.lang.String</literal> a
+ <literal>VARCHAR</literal> (u Oracle <literal>VAARCHAR2</literal>).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>date, time, timestamp</literal></term>
+ <listitem>
+ <para>
+ Mapeos de tipo desde <literal>java.util.Date</literal> y sus subclases
+ a tipos SQL <literal>DATE</literal>, <literal>TIME</literal> y
+ <literal>TIMESTAMP</literal> (o equivalente).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>calendar, calendar_date</literal></term>
+ <listitem>
+ <para>
+ Mapeos de tipo desde <literal>java.util.Date</literal> y sus subclases
+ a tipos SQL <literal>TIMESTAMP</literal> y <literal>DATE</literal>
+ (o equivalente).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>big_decimal, big_integer</literal></term>
+ <listitem>
+ <para>
+ Mapeos de tipo desde <literal>java.math.BigDecimal</literal> y
+ <literal>java.math.BigInteger</literal> a <literal>NUMERIC</literal>
+ (o <literal>NUMBER</literal> de Oracle).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>locale, timezone, currency</literal></term>
+ <listitem>
+ <para>
+ Mapeos de tipo desde <literal>java.util.Locale</literal>,
+ <literal>java.util.TimeZone</literal> y
+ <literal>java.util.Currency</literal> a
+ <literal>VARCHAR</literal> (o <literal>VARCHAR2</literal> de Oracle).
+ Las instancias de <literal>Locale</literal> y <literal>Currency</literal>
+ son mapeadas a sus códigos ISO. Las instancias de
+ <literal>TimeZone</literal> son mapeadas a sus <literal>ID</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>class</literal></term>
+ <listitem>
+ <para>
+ Un mapeo de tipo <literal>java.lang.Class</literal> a
+ <literal>VARCHAR</literal> (o <literal>VARCHAR2</literal> de Oracle).
+ Una <literal>Class</literal> es mapeara a su nombre completamente
+ cualificado.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>binary</literal></term>
+ <listitem>
+ <para>
+ Mapea arreglos de bytes a un tipo binario SQL apropiado.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>text</literal></term>
+ <listitem>
+ <para>
+ Mapea cadenas largas Java al tipo SQL <literal>CLOB</literal> o
+ <literal>TEXT</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>serializable</literal></term>
+ <listitem>
+ <para>
+ Mapea tipos serializables Java a un tipo binario SQL apropiado.
+ Puedes además indicar el tipo <literal>serializable</literal>
+ de Hibernate con el nombre de una clase o interface serializable Java
+ que no sea por defecto un tipo básico.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>clob, blob</literal></term>
+ <listitem>
+ <para>
+ Mapeos de tipo para las clases JDBC <literal>java.sql.Clob</literal> y
+ <literal>java.sql.Blob</literal>. Estos tipos pueden ser inconvenientes
+ para algunas aplicaciones, pues el objeto blob o clob no puede ser reusado
+ fuera de una transacción (Además, el soporte del driver suele
+ ser malo e inconsistente).
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ </para>
+
+ <para>
+ Los identificadores únicos de entidades y collecciones pueden ser de cualquier
+ tipo básico excepto <literal>binary</literal>, <literal>blob</literal>
+ y <literal>clob</literal>.
+ (Los identificadores compuestos están también permitidos, ver debajo.)
+ </para>
+
+ <para>
+ Los tipos de valor básicos tienen sus constantes <literal>Type</literal>
+ correspondientes definidas en <literal>org.hibernate.Hibernate</literal>. Por ejemplo,
+ <literal>Hibernate.STRING</literal> representa el tipo <literal>string</literal>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-types-custom" revision="2">
+ <title>Tipos de valor personalizados</title>
+
+ <para>
+ Es relativamente fácil para los desarrolladores crear sus propios tipos de valor.
+ Por ejemplo, podrías querer persistir propiedades del tipo <literal>java.lang.BigInteger</literal>
+ a columnas <literal>VARCHAR</literal>. Hibernate no provee un tipo de fábrica para esto.
+ Pero los tipos personalizados no están limitados a mapear una propiedad (o elemento de colección)
+ a una sola columna de tabla. Así, por ejemplo, podrías tener una propiedad Java
+ <literal>getName()</literal>/<literal>setName()</literal> de tipo <literal>java.lang.String</literal>
+ que fuera persistida a las columnas <literal>FIRST_NAME</literal>, <literal>INITIAL</literal>,
+ <literal>SURNAME</literal>.
+ </para>
+
+ <para>
+ Para implementar un tipo personalizado, implementa bien <literal>org.hibernate.UserType</literal>
+ o <literal>org.hibernate.CompositeUserType</literal> y declara las propiedades usando el nombre
+ de clase completamente cualificado del tipo. Revisa <literal>org.hibernate.test.DoubleStringType</literal>
+ para ver qué tipo de cosas son posibles.
+ </para>
+
+ <programlisting><![CDATA[<property name="twoStrings" type="org.hibernate.test.DoubleStringType">
+ <column name="first_string"/>
+ <column name="second_string"/>
+</property>]]></programlisting>
+
+ <para>
+ Observa el uso de etiquetas <literal><column></literal> para mapear una propiedad
+ a múltiples columnas.
+ </para>
+
+ <para>
+ Las interfaces <literal>CompositeUserType</literal>, <literal>EnhancedUserType</literal>,
+ <literal>UserCollectionType</literal>, y <literal>UserVersionType</literal> proveen
+ soporte a usos más especializados.
+ </para>
+
+ <para>
+ Puedes incluso proveer de parámetros a un <literal>UserType</literal> en el
+ fichero de mapeo. Para hacer esto, tu <literal>UserType</literal> debe implementar
+ la interface <literal>org.hibernate.usertype.ParameterizedType</literal>. Para
+ proveer de parámetros a tu tipo personalizado, puedes usar el elemento
+ <literal><type></literal> en tus ficheros de mapeo.
+ </para>
+
+ <programlisting><![CDATA[<property name="priority">
+ <type name="com.mycompany.usertypes.DefaultValueIntegerType">
+ <param name="default">0</param>
+ </type>
+</property>]]></programlisting>
+
+ <para>
+ Ahora el <literal>UserType</literal> puede recuperar el valor del parámetro
+ llamado <literal>default</literal> del objeto <literal>Properties</literal>
+ que se le pasa.
+ </para>
+
+ <para>
+ Si usas cierto <literal>UserType</literal> muy frecuentemente, puede ser útil
+ definir un nombre corto para é. Puedes hacer esto usando el elemento
+ <literal><typedef></literal>. Los typedefs asignan un nombre a un tipo
+ personalizado, y pueden también contener una lista de valores por defecto
+ de parámetros si el tipo fuese parametrizado.
+ </para>
+
+ <programlisting><![CDATA[<typedef class="com.mycompany.usertypes.DefaultValueIntegerType" name="default_zero">
+ <param name="default">0</param>
+</typedef>]]></programlisting>
+
+ <programlisting><![CDATA[<property name="priority" type="default_zero"/>]]></programlisting>
+
+ <para>
+ también es posible sobrescribir los parámetros provistos en un typedef sobre
+ una base caso por caso usando parámetros de tipo en el mapeo de la propiedad.
+ </para>
+
+ <para>
+ Aunque el rico espectro de tipos prefabricados y soporte de componentes de Hibernate
+ significa que raramente <emphasis>necesites</emphasis> usar un tipo personalizado;
+ sin embargo se considera una buena forma usar tipos personalizados para clases (no-entidades)
+ que aparezcan frecuentemente en tu aplicación. Por ejemplo, una clase
+ <literal>MonetaryAmount</literal> es una buena candidata para un
+ <literal>CompositeUserType</literal>, incluso cuando puede ser facilmente mapeada como un
+ componente. Un motivo para esto es la abstracción. Con un tipo personalizado,
+ tus documentos de mapeo estará impermeabilizados contra posibles cambios futuros en la
+ forma de representar valores monetarios.
+ </para>
+ </sect2>
+
+ </sect1>
+
+
+ <sect1 id="mapping-entityname">
+ <title>Mapeando una clase más de una vez</title>
+ <para>
+ Es posible proveer más de un mapeo para una clase persistente en particular. En este caso debes
+ especificar un <emphasis>nombre de entidad</emphasis> para desambiguar entr las instancias de las
+ dos entidades mapeadas. (Por defectom, el nombre de la entidad es el mismo que el nombre de la clase.)
+ Hibernate te deja especificar el nombre de entidad al trabajar con objetos persistentes, al escribir
+ consultas, o al mapear asociaciones a la entidad mencionada.
+ </para>
+
+ <programlisting><![CDATA[<class name="Contract" table="Contracts"
+ entity-name="CurrentContract">
+ ...
+ <set name="history" inverse="true"
+ order-by="effectiveEndDate desc">
+ <key column="currentContractId"/>
+ <one-to-many entity-name="HistoricalContract"/>
+ </set>
+</class>
+
+<class name="Contract" table="ContractHistory"
+ entity-name="HistoricalContract">
+ ...
+ <many-to-one name="currentContract"
+ column="currentContractId"
+ entity-name="CurrentContract"/>
+</class>]]></programlisting>
+
+ <para>
+ Observa cómo las asociaciones ahora se especifican usando <literal>entity-name</literal> en vez de
+ <literal>class</literal>.
+ </para>
+
+ </sect1>
+
+
+ <sect1 id="mapping-quotedidentifiers">
+ <title>identificadores SQL encomillados</title>
+ <para>
+ Puedes forzar a Hibernate a encomillar un identificador en el SQL generado encerrando el nombre
+ de tabla o columna entre backticks en el documento de mapeo. Hibernate usará el estilo de
+ encomillado para el <literal>Dialect</literal> SQL (usualmente comillas dobles, excepto corchetes
+ para SQL Server y backsticks para MySQL).
+ </para>
+
+ <programlisting><![CDATA[<class name="LineItem" table="`Line Item`">
+ <id name="id" column="`Item Id`"/><generator class="assigned"/></id>
+ <property name="itemNumber" column="`Item #`"/>
+ ...
+</class>]]></programlisting>
+
+ </sect1>
+
+
+ <sect1 id="mapping-alternatives">
+ <title>Alternativas de metadatos</title>
+
+ <para>
+ XML no es para todos, asá que hay algunas formas alternativas de definir metadatos de mapeo O/R
+ en Hibernate.
+ </para>
+
+ <sect2 id="mapping-xdoclet">
+ <title>Usando marcado de XDoclet</title>
+
+ <para>
+ Muchos usuarios de Hibernate prefieren embeber la información de mapeo directamente
+ en el código fuente usando las <literal>@hibernate.etiquetas</literal> XDoclet.
+ No cubriremos este enfoque en este documento, pues estrictamente es considerado parte
+ de XDoclet. Sin embargo, incluímos el siguiente ejemplo de la clase
+ <literal>Cat</literal> con mapeos XDoclet.
+ </para>
+
+ <programlisting><![CDATA[package eg;
+import java.util.Set;
+import java.util.Date;
+
+/**
+ * @hibernate.class
+ * table="CATS"
+ */
+public class Cat {
+ private Long id; // identifier
+ private Date birthdate;
+ private Cat mother;
+ private Set kittens
+ private Color color;
+ private char sex;
+ private float weight;
+
+ /*
+ * @hibernate.id
+ * generator-class="native"
+ * column="CAT_ID"
+ */
+ public Long getId() {
+ return id;
+ }
+ private void setId(Long id) {
+ this.id=id;
+ }
+
+ /**
+ * @hibernate.many-to-one
+ * column="PARENT_ID"
+ */
+ public Cat getMother() {
+ return mother;
+ }
+ void setMother(Cat mother) {
+ this.mother = mother;
+ }
+
+ /**
+ * @hibernate.property
+ * column="BIRTH_DATE"
+ */
+ public Date getBirthdate() {
+ return birthdate;
+ }
+ void setBirthdate(Date date) {
+ birthdate = date;
+ }
+ /**
+ * @hibernate.property
+ * column="WEIGHT"
+ */
+ public float getWeight() {
+ return weight;
+ }
+ void setWeight(float weight) {
+ this.weight = weight;
+ }
+
+ /**
+ * @hibernate.property
+ * column="COLOR"
+ * not-null="true"
+ */
+ public Color getColor() {
+ return color;
+ }
+ void setColor(Color color) {
+ this.color = color;
+ }
+ /**
+ * @hibernate.set
+ * inverse="true"
+ * order-by="BIRTH_DATE"
+ * @hibernate.collection-key
+ * column="PARENT_ID"
+ * @hibernate.collection-one-to-many
+ */
+ public Set getKittens() {
+ return kittens;
+ }
+ void setKittens(Set kittens) {
+ this.kittens = kittens;
+ }
+ // addKitten not needed by Hibernate
+ public void addKitten(Cat kitten) {
+ kittens.add(kitten);
+ }
+
+ /**
+ * @hibernate.property
+ * column="SEX"
+ * not-null="true"
+ * update="false"
+ */
+ public char getSex() {
+ return sex;
+ }
+ void setSex(char sex) {
+ this.sex=sex;
+ }
+}]]></programlisting>
+
+ <para>
+ Para más ejemplos de XDoclet e Hibernate ver en el sitio web de Hibernate.
+ </para>
+
+ </sect2>
+
+ <sect2 id="mapping-annotations" revision="2">
+ <title>Usando anotaciones JDK 5.0</title>
+ <para>
+ El JDK 5.0 introdujo anotaciones del estilo XDoclet a nivel del lenguaje,
+ con chequeo seguro de tipos en tiempo de compilación. Este mecanismo es más
+ potente y que las anotaciones XDoclet, y mejor soportado por herramientas e IDEs.
+ IntelliJ IDEA, por ejemplo, soporta auto-compleción y resaltado de sintaxis de anotaciones
+ JDK 5.0. La nueva revisión de la especificación de EJB (JSR-220) usa anotaciones
+ JDK 5.0 como el mecanismo primario de metadatos para beans de entidad. Hibernate3 implementa
+ el <literal>EntityManager</literal> del JSR-220 (la API de persistencia), y el soporte para
+ metadatos de mapeo está disponible vía el paquete <emphasis>Hibernate Annotations</emphasis>,
+ como una descarga por separado. Tanto metadatos de EJB3 (JSR-220) como de Hibernate3 están soportados.
+ </para>
+
+ <para>
+ Este es un ejemplo de una clase POJO anotada como un bean de entidad EJB:
+ </para>
+
+ <programlisting><![CDATA[@Entity(access = AccessType.FIELD)
+public class Customer implements Serializable {
+
+ @Id;
+ Long id;
+
+ String firstName;
+ String lastName;
+ Date birthday;
+
+ @Transient
+ Integer age;
+
+ @Embedded
+ private Address homeAddress;
+
+ @OneToMany(cascade=CascadeType.ALL)
+
+ @JoinColumn(name="CUSTOMER_ID")
+ Set<Order> orders;
+
+ // Getter/setter and business methods
+}]]></programlisting>
+
+ <para>
+ Ten en cuenta que el soporte a anotaciones JDK 5.0 (y JSR-220) es todavía un
+ trabajo en progreso y no completado. Por favor, para más detalles refiérete al modulo
+ de Anotaciones de Hibernate.
+ </para>
+
+ </sect2>
+ </sect1>
+
+</chapter>
+
+
+
+
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/content/batch.xml (from rev 12794, core/trunk/documentation/manual/es-ES/src/main/docbook/modules/batch.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/batch.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/batch.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,192 @@
+<chapter id="batch">
+ <title>Procesamiento por lotes</title>
+
+ <para>
+ Un enfoque ingenuo para insertar 100.000 filas en la base de datos usando Hibernate podría verse así:
+ </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+for ( int i=0; i<100000; i++ ) {
+ Customer customer = new Customer(.....);
+ session.save(customer);
+}
+tx.commit();
+session.close();]]></programlisting>
+
+ <para>
+ Esto podría caer sobre una <literal>OutOfMemoryException</literal> en algún sitio
+ cerca de la fila 50.000. Esto es porque Hibernate tiene en caché todas las instancias
+ de <literal>Customer</literal> recién instanciadas en el caché de nivel de sesión.
+ </para>
+
+ <para>
+ En este capítulo te mostraremos cómo evitar este problema. Primero, sin embargo,
+ si estás haciendo procesamiento por lotes (batch processing), es absolutamente crítico
+ que habilites el uso de loteo JDBC, si pretendes lograr un rendimiento razonable.
+ Establece el tamaño de lote JDBC a un número razonable (digamos 10-50):
+ </para>
+
+<programlisting><![CDATA[hibernate.jdbc.batch_size 20]]></programlisting>
+
+ <para>
+ Podrías además querer hacer este tipo de trabajo en un proceso donde la interacción con el caché de
+ segundo nivel esté completamente deshabilitado:
+ </para>
+
+<programlisting><![CDATA[hibernate.cache.use_second_level_cache false]]></programlisting>
+
+ <sect1 id="batch-inserts">
+ <title>Inserciones en lote</title>
+
+ <para>
+ Al hacer persistentes objetos nuevos, debes limpiar con <literal>flush()</literal> y
+ llamar a <literal>clear()</literal> en la sesión regularmente, para controlar el tamaño
+ del caché de primer nivel.
+ </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+for ( int i=0; i<100000; i++ ) {
+ Customer customer = new Customer(.....);
+ session.save(customer);
+ if ( i % 20 == 0 ) { //20, same as the JDBC batch size
+ //flush a batch of inserts and release memory:
+ session.flush();
+ session.clear();
+ }
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="batch-update" >
+ <title>Actualizaciones en lote</title>
+
+ <para>
+ Para recuperar y actualizar datos se aplican las mismas ideas. Adicionalmente, necesitas usar
+ <literal>scroll()</literal> para sacar ventaja de los cursores del lado del servidor en consultas
+ que devuelvan muchas filas de datos.
+ </para>
+
+<programlisting><![CDATA[Session session = sessionFactory.openSession();
+Transaction tx = session.beginTransaction();
+
+ScrollableResults customers = session.getNamedQuery("GetCustomers")
+ .setCacheMode(CacheMode.IGNORE)
+ .scroll(ScrollMode.FORWARD_ONLY);
+int count=0;
+while ( customers.next() ) {
+ Customer customer = (Customer) customers.get(0);
+ customer.updateStuff(...);
+ if ( ++count % 20 == 0 ) {
+ //flush a batch of updates and release memory:
+ session.flush();
+ session.clear();
+ }
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="batch-direct">
+ <title>update/delete en masa</title>
+
+ <para>
+ Como ya se ha discutido, el mapeo objeto/relacional automático y transparente se refiere
+ al manejo de estado de objetos. Esto implica que el estado del objeto está disponible
+ en memoria, por lo tanto actualizar o borrar (usando <literal>UPDATE</literal> y
+ <literal>DELETE</literal> de SQL) datos directamente en la base de datos no afectará el
+ estado en memoria. Sin embargo, Hibernate provee métodos para la ejecución de sentencias
+ del estilo de <literal>UPDATE</literal> y <literal>DELETE</literal> de SQL que se realizan
+ a través del Lenguaje de Consulta de Hibernate (Hibernate Query Language o
+ <xref linkend="queryhql">HQL</xref>).
+ </para>
+
+ <para>
+ La pseudo-sintáxis para sentencias <literal>UPDATE</literal> y <literal>DELETE</literal> es:
+ <literal>( UPDATE | DELETE ) FROM? ClassName (WHERE WHERE_CONDITIONS)?</literal>. Algunos puntos
+ a tener en cuenta:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ En la cláusula-from, la palabra clave FROM es opcional
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Puede haber sólo una clase mencionada en la cláusula-from, y <emphasis>no puede</emphasis>
+ tener un alias.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ No puede especificarse ningún join (bien implícito o explícito) en una consulta masiva de HQL.
+ Pueden usarse subconsultas en la cláusula-where.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ La cláusula-where es también opcional.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Como un ejemplo, para ejecutar un <literal>UPDATE</literal> HQL, usa el
+ método <literal>Query.executeUpdate()</literal>:
+ </para>
+
+ <programlisting><![CDATA[Session session = sessionFactory.openSession();
+ Transaction tx = session.beginTransaction();
+
+ String hqlUpdate = "update Customer set name = :newName where name = :oldName";
+ int updatedEntities = s.createQuery( hqlUpdate )
+ .setString( "newName", newName )
+ .setString( "oldName", oldName )
+ .executeUpdate();
+ tx.commit();
+ session.close();]]></programlisting>
+
+ <para>
+ Para ejecutar un <literal>DELETE</literal> HQL, usa el mismo método <literal>Query.executeUpdate()</literal>
+ (el método está nombrado para aquellos familiarizados con
+ <literal>PreparedStatement.executeUpdate()</literal> de JDBC):
+ </para>
+
+ <programlisting><![CDATA[Session session = sessionFactory.openSession();
+ Transaction tx = session.beginTransaction();
+
+ String hqlDelete = "delete Customer where name = :oldName";
+ int deletedEntities = s.createQuery( hqlDelete )
+ .setString( "oldName", oldName )
+ .executeUpdate();
+ tx.commit();
+ session.close();]]></programlisting>
+
+ <para>
+ El valor <literal>int</literal> devuelto por el método <literal>Query.executeUpdate()</literal>
+ indica el número de entidades afectadas por la operación. Considera que esto puede o no
+ correlacionarse al número de filas afectadas en la base de datos. Una operación masiva HQL podría
+ resultar en que se ejecuten múltiples sentencias de SQL reales, para joined-subclass, por ejemplo.
+ El número devuelto indica el número de entidades reales afectadas por la sentencia. Volviendo al
+ ejemplo de joined-subclass, un borrado contra una de las subclases puede resultar realmente en
+ borrados contra no sólo la tabla a la que está mapeada esa subclase, sino también la tabla "raíz"
+ y potencialmente tablas de joined-subclass más debajo en la jerarquía de herencia.
+ </para>
+
+ <para>
+ Ten en cuenta que existen actualmente unas pocas limitaciones con las operaciones HQL masivas,
+ que serán atendidas en lanzamientos futuros; consulta la hoja de ruta de JIRA para más detalles.
+ </para>
+
+ </sect1>
+
+</chapter>
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/content/best_practices.xml (from rev 12794, core/trunk/documentation/manual/es-ES/src/main/docbook/modules/best_practices.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/best_practices.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/best_practices.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,229 @@
+<chapter id="best-practices" revision="3">
+ <title>Mejores Prácticas</title>
+
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term>Escribe clase finamente granularizadas y mapealas usando <literal><component></literal>.</term>
+ <listitem>
+ <para>
+ Usa una clase <literal>Dirección</literal> para encapsular <literal>calle</literal>,
+ <literal>distrito</literal>, <literal>estado</literal>, <literal>código postal</literal>.
+ Esto alienta la reutilización de código y simplifica el refactoring.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Declara las propiedades identificadoras en clases persistentes.</term>
+ <listitem>
+ <para>
+ Hibernate hace opcionales las propiedades identificadoras. Existen todo tipo de razones
+ por las que debes usarlas. Recomendamos que los identificadores sean 'sintéticos'
+ (generados, sin ningún significado de negocio).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Identifica las claves naturales.</term>
+ <listitem>
+ <para>
+ Identifica las claves naturales de todas las entidades, y mapealas usando
+ <literal><natural-id></literal>. Implementa <literal>equals()</literal> y
+ <literal>hashCode()</literal> para comparar las propiedades que componen la clave natural.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Coloca cada mapeo de clase en su propio fichero.</term>
+ <listitem>
+ <para>
+ No uses un solo documento monolítico de mapeo. Mapea <literal>com.eg.Foo</literal> en
+ el fichero <literal>com/eg/Foo.hbm.xml</literal>. Esto tiene sentido particularmente en un
+ ambiente de equipo.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Carga los mapeos como recursos.</term>
+ <listitem>
+ <para>
+ Despliega los mapeos junto a las clases que mapean.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Considera externalizar las cadenas de consulta.</term>
+ <listitem>
+ <para>
+ Esta es una buena práctica si tus consultas llaman a funciones SQL que no son del
+ estándar ANSI. Externalizar las cadenas de consulta a ficheros de mapeo hará la
+ aplicación más portable.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Usa variables de ligado.</term>
+ <listitem>
+ <para>
+ Igual que en JDBC, siempre remplaza valores no constantes con "?". ¡Nunca uses manipulación
+ de cadenas para ligar un valor no constante en una consulta! Incluso mejor, considera usar
+ parámetros con nombre en las consultas.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>No manejes tus propias conexiones JDBC.</term>
+ <listitem>
+ <para>
+ Hibernate deja a la aplicación administre las conexiones JDBC. Este enfoque debe considerarse
+ como último recurso. Si no puedes usar los provedores de conexión prefabricados, considera
+ prover tu propia implementación de <literal>org.hibernate.connection.ConnectionProvider</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Considera usar un tipo personalizado.</term>
+ <listitem>
+ <para>
+ Supón que tienes un tipo Java, digamos de alguna biblioteca, que necesita hacerse persistente
+ pero no provee los métodos de acceso necesarios para mapearlo como un componente. Debes considerar
+ implementar <literal>org.hibernate.UserType</literal>. Este enfoque libera al código de aplicación
+ de implementar transformaciones a / desde un tipo Hibernate.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Usa JDBC codificado a mano en cuellos de botella.</term>
+ <listitem>
+ <para>
+ En áreas del sistema de rendimiento crítico, algunos tipos de operaciones podrían beneficiarse
+ del JDBC directo. Pero por favor, espero hasta que <emphasis>sepas</emphasis> que algo es
+ un cuello de botella. Y no asumas que el JDBC directo es necesariamente más rápido. Si necesitas
+ usar JDBC directo, podría ser valioso abrir una <literal>Session</literal> de Hibernate y usar esa
+ conexión JDBC. De esta forma puedes usar aún la misma estrategia de transacción y el mismo
+ proveedor de conexiones subyacente.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Comprende la limpieza (flushing) de <literal>Session</literal>.</term>
+ <listitem>
+ <para>
+ De vez en cuando la sesión sincroniza su estado persistente con la base de datos. El rendimiento
+ se verá afectado si este proceso ocurre demasiado frecuentemente. A veces puedes minimizar
+ limpieza innecesaria deshabilitando la limpieza automática o incluso cambiando el orden de las
+ consultas u otras operaciones en una transacción en particular.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>En una aplicación en tres gradas, considera usar objetos separados.</term>
+ <listitem>
+ <para>
+ Al usar una arquitectura de servlet / sesión, puedes pasar objetos persistentes en el bean de
+ sesión hacia y desde la capa de servlet / JSP. Usa una sesión nueva para atender el servicio de cada
+ petición. Usa <literal>Session.merge()</literal> o <literal>Session.saveOrUpdate()</literal> para
+ sincronizar los objetos con la base de datos.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>En una arquitectura en dos gradas, considera usar contexto de persistencia largos.</term>
+ <listitem>
+ <para>
+ Las transacciones de base de datos tienen que ser tan cortas como sea posible. Sin embargo,
+ frecuentemente es necesario implementar <emphasis>transacciones de aplicación</emphasis>
+ ejecutándose en largo, una sola unidad de trabajo desde el punto de vista de un usuario.
+ Una transacción de aplicación puede abarcar muchos ciclos petición/respuesta del cliente.
+ Es común usar objetos separados para implementar transacciones de aplicación. Una alternativa,
+ extremadamente apropiada en arquitecturas en dos gradas, es mantener un solo contacto de persistencia
+ abierto (sesión) para todo el ciclo de vida de la transacción de aplicación y simplemente
+ desconectar de la conexión JDBC al final de cada petición, y reconectar al comienzo de la
+ petición subsecuente. Nunca compartas una única sesión a través de más de una transacción
+ de aplicación, o estarás trabajando con datos añejos.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>No trates la excepciones como recuperables.</term>
+ <listitem>
+ <para>
+ Esto es más una práctica necesaria que una "mejor" práctica. Cuando ocurra una excepción,
+ deshaz (rollback) la <literal>Transaction</literal> y cierra la <literal>Session</literal>.
+ Si no lo haces, Hibernate no puede garantizar que el estado en memoria representa con exactitud
+ el estado persistente. Como un caso especial de esto, no uses <literal>Session.load()</literal>
+ para determinar si una instancia con el identificador dado existe en la base de datos. En cambio,
+ usa <literal>Session.get()</literal> o una consulta.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Prefiere la recuperación perezosa para las asociaciones.</term>
+ <listitem>
+ <para>
+ Usa escasamente la recuperación temprana. Usa proxies y colecciones perezosas para la mayoría
+ de asociaciones a clases probablemente no estén mantenidas en el caché de segundo nivel. Para
+ las asociaciones a clases en caché, donde hay una probabilidad de acceso a caché extremadamente
+ alta, deshabilita explícitamente la recuperación temprana usando <literal>lazy="false"</literal>.
+ Cuando sea apropiada la recuperación por unión (join fetching) para un caso de uso en particular,
+ usa una consulta con un <literal>left join fetch</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ Usa el patrón <emphasis>sesión abierta en vista</emphasis>, o una <emphasis>fase de ensamblado</emphasis>
+ disciplinada para evitar problemas con datos no recuperados.
+ </term>
+ <listitem>
+ <para>
+ Hibernate liberal al desarrollador de escribir <emphasis>Objetos de Transferencia de Datos
+ (Data Transfer Objects)</emphasis> (DTO). En una arquitectura tradicional de EJB, los DTOs tienen
+ un propósito doble: primero, atacan el problema que los beans de entidad no son serializables.
+ Segundo, definen implícitamente una fase de ensamblado cuando se recuperan y se forman (marshalling)
+ todos los datos a usar por la vista en los DTOs antes de devolver el control a la grada de
+ presentación. Hibernate elimina el primer propósito. Sin embargo, aún necesitas una fase
+ de ensamblado (piensa en tus métodos de negocio como si tuviesen un contrato estricto con la grada
+ de presentación sobre qué datos están disponibles en los objetos separados) a menos que estés
+ preparado para tener el contexto de persistencia (la sesión) abierto a través del proceso
+ de renderización de la vista. ¡Esta no es una limitación de Hibernate! Es un requerimiento
+ fundamental de acceso seguro a datos transaccionales.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Considera abstraer tu lógica de negocio de Hibernate</term>
+ <listitem>
+ <para>
+ Oculta el código de acceso a datos (Hibernate) detrás de una interface. Combina los patrones
+ <emphasis>DAO</emphasis> y <emphasis>Sesión de Hebra Local</emphasis>. Incluso puedes tener
+ algunas clases hechas persistentes por JDBC escrito a mano, asociadas a Hibernate por medio
+ de un <literal>UserType</literal>. (Este consejo está pensado para aplicaciones "suficientemente
+ grandes"; ¡no es apropiado para una aplicación con cinco tablas!)
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>No uses mapeos de asociación exóticos.</term>
+ <listitem>
+ <para>
+ Son raros los casos de uso de asociaciones reales muchos-a-muchos. La mayor parte del tiempo
+ necesitas información adicional almacenada en una "tabla de enlace". En este caso, es mucho
+ mejor usar dos asociaciones uno-a-muchos a una clase de enlace intermedia. De hecho, pensamos
+ que la mayoría de asociaciones son uno-a-muchos y muchos-a-uno, debes ser cuidadoso al usr
+ cualquier otro estilo de asociación y preguntarte si es realmente necesario.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Prefiere las asociaciones bidireccionales.</term>
+ <listitem>
+ <para>
+ Las asociaciones unidireccionales son más difíciles de consultar. En una aplicación grande,
+ casi todas las asociaciones deben ser navegables en ambas direcciones en consultas.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+</chapter>
+
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/content/collection_mapping.xml (from rev 12794, core/trunk/documentation/manual/es-ES/src/main/docbook/modules/collection_mapping.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/collection_mapping.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/collection_mapping.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,1241 @@
+<chapter id="collections">
+ <title>Mapeo de Colecciones</title>
+
+ <sect1 id="collections-persistent" revision="3">
+ <title>Colecciones persistentes</title>
+
+ <para>
+ Hibernate requiere que los campos valuados en colección
+ persistentes sean declarados como un tipo de interface, por ejemplo:
+ </para>
+
+ <programlisting><![CDATA[public class Product {
+ private String serialNumber;
+ private Set parts = new HashSet();
+
+ public Set getParts() { return parts; }
+ void setParts(Set parts) { this.parts = parts; }
+ public String getSerialNumber() { return serialNumber; }
+ void setSerialNumber(String sn) { serialNumber = sn; }
+}]]></programlisting>
+
+ <para>
+ La interface real podría ser <literal>java.util.Set</literal>,
+ <literal>java.util.Collection</literal>, <literal>java.util.List</literal>,
+ <literal>java.util.Map</literal>, <literal>java.util.SortedSet</literal>,
+ <literal>java.util.SortedMap</literal> o ... lo que te guste!
+ (Donde "lo que te guste" significa que tendrás que escribir una
+ implementación de <literal>org.hibernate.usertype.UserCollectionType</literal>.)
+ </para>
+
+ <para>
+ Nota cómo hemos inicializado la variable de instancia de
+ <literal>HashSet</literal>. Esta es la mejor forma de inicializar
+ propiedades valuadas en colección de instancias recién
+ instanciadas (no persistentes). Cuando haces persistente la instancia
+ - llamando a <literal>persist()</literal>, por ejemplo - Hibernate realmente
+ remplazará el <literal>HashSet</literal> con una instancia de una
+ implementación de <literal>Set</literal> propia de Hibernate.
+ Observa errores como este:
+ </para>
+
+ <programlisting><![CDATA[Cat cat = new DomesticCat();
+Cat kitten = new DomesticCat();
+....
+Set kittens = new HashSet();
+kittens.add(kitten);
+cat.setKittens(kittens);
+session.persist(cat);
+kittens = cat.getKittens(); // Okay, kittens collection is a Set
+(HashSet) cat.getKittens(); // Error!]]></programlisting>
+
+ <para>
+ Las colecciones persistentes inyectadas por Hibernate se comportan
+ como <literal>HashMap</literal>, <literal>HashSet</literal>,
+ <literal>TreeMap</literal>, <literal>TreeSet</literal> o
+ <literal>ArrayList</literal>, dependiendo del tipo de interface.
+ </para>
+
+ <para>
+ Las instancias de colecciones tienen el comportamiento usual de tipos de valor.
+ Son automáticamente persistidas al ser referenciadas por un objeto
+ persistente y automáticamente borradas al desreferenciarse. Si una
+ colección es pasada de un objeto persistente a otro, sus elementos
+ serían movidos de una tabla a otra. Dos entidades pueden no
+ compartir una referencia a la misma instancia de colección.
+ Debido al modelo relacional subyacente, las propiedades valuadas en
+ colección no soportan la semántica de valor nulo. Hibernate no
+ distingue entre una referencia de colección nula y una colección
+ vacía.
+ </para>
+
+ <para>
+ No debes tener que preocuparte demasiado por esto. Usa las colecciones
+ persistentes de la misma forma en que usas colecciones de Java ordinarias.
+ Sólo asegúrate que entiendes la semántica de las asociaciones
+ bidireccionales (discutida luego).
+ </para>
+
+ </sect1>
+
+ <sect1 id="collections-mapping" revision="2">
+ <title>Mapeos de colección</title>
+
+ <para>
+ El elemento de mapeo de Hibernate usado para mapear una colección
+ depende del tipo de la interface. Por ejemplom un elemento
+ <literal><set></literal> se usa para mapear propiedades de tipo
+ <literal>Set</literal>.
+ </para>
+
+ <programlisting><![CDATA[<class name="Product">
+ <id name="serialNumber" column="productSerialNumber"/>
+ <set name="parts">
+ <key column="productSerialNumber" not-null="true"/>
+ <one-to-many class="Part"/>
+ </set>
+</class>]]></programlisting>
+
+ <para>
+ Aparte de <literal><set></literal>, existen además
+ los elementos de mapeo <literal><list></literal>,
+ <literal><map></literal>, <literal><bag></literal>,
+ <literal><array></literal> y <literal><primitive-array></literal>.
+ El elemento <literal><map></literal> es representativo:
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="mappingcollection1" coords="2 65"/>
+ <area id="mappingcollection2" coords="3 65"/>
+ <area id="mappingcollection3" coords="4 65"/>
+ <area id="mappingcollection4" coords="5 65"/>
+ <area id="mappingcollection5" coords="6 65"/>
+ <area id="mappingcollection6" coords="7 65"/>
+ <area id="mappingcollection7" coords="8 65"/>
+ <area id="mappingcollection8" coords="9 65"/>
+ <area id="mappingcollection9" coords="10 65"/>
+ <area id="mappingcollection10" coords="11 65"/>
+ <area id="mappingcollection11" coords="12 65"/>
+ <area id="mappingcollection12" coords="13 65"/>
+ <area id="mappingcollection13" coords="14 65"/>
+ </areaspec>
+ <programlisting><![CDATA[<map
+ name="propertyName"
+ table="table_name"
+ schema="schema_name"
+ lazy="true|false"
+ inverse="true|false"
+ cascade="all|none|save-update|delete|all-delete-orphan"
+ sort="unsorted|natural|comparatorClass"
+ order-by="column_name asc|desc"
+ where="arbitrary sql where condition"
+ fetch="join|select|subselect"
+ batch-size="N"
+ access="field|property|ClassName"
+ optimistic-lock="true|false"
+ node="element-name|."
+ embed-xml="true|false"
+>
+
+ <key .... />
+ <map-key .... />
+ <element .... />
+</map>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="mappingcollection1">
+ <para>
+ <literal>name</literal> el nombre de la propiedad de colección
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection2">
+ <para>
+ <literal>table</literal> (opcional - por defecto al nombre de la propiedad)
+ el nombre de la tabla de coleciión (no usado para asociaciones
+ uno-a-muchos)
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection3">
+ <para>
+ <literal>schema</literal> (opcional) el nombre de un esquema de tablas
+ para sobrescribir el esquema declarado en el elemento raíz
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection4">
+ <para>
+ <literal>lazy</literal> (opcional - por defecto a <literal>true</literal>)
+ puede ser usado para deshabilitar la recuperación perezosa y
+ especificar que la asociación es siempre recuperada tempranamente
+ (no disponible para arrays)
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection5">
+ <para>
+ <literal>inverse</literal> (opcional - por defecto a <literal>false</literal>)
+ marca esta colección como el extremo "inverso" de una asociación
+ bidireccional.
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection6">
+ <para>
+ <literal>cascade</literal> (opcional - por defecto a <literal>none</literal>)
+ habilita operaciones en cascada a entidades hijas
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection7">
+ <para>
+ <literal>sort</literal> (opcional) especifica una colección
+ con ordenamiento <literal>natural</literal>, o una clase comparadora
+ dada
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection8">
+ <para>
+ <literal>order-by</literal> (opcional, sólo JDK1.4) especifica una columna
+ de tabla (o columnas) que definen el orden de iteración del
+ <literal>Map</literal>, <literal>Set</literal> o bag, junto a un
+ <literal>asc</literal> o <literal>desc</literal> opcional.
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection9">
+ <para>
+ <literal>where</literal> (opcional) especifica una condición
+ <literal>WHERE</literal> de SQL arbitrario para ser usada al recuperar o
+ quitar la colección (útil si la colección debe
+ contener sólo un subconjunto de los datos disponibles)
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection10">
+ <para>
+ <literal>fetch</literal> (opcional, por defecto a <literal>select</literal>)
+ Elige entre recuperación por unión externa (outer-join),
+ recuperar por selección secuencial, y recuperación por
+ subselección secuencial.
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection11">
+ <para>
+ <literal>batch-size</literal> (opcional, por defecto a <literal>1</literal>)
+ especifica un "tamaño de lote" para la recuperar
+ perezosamente instancias de esta colección.
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection12">
+ <para>
+ <literal>access</literal> (opcional - por defecto a <literal>property</literal>):
+ La estrategia que debe usar Hibernate para acceder al valor de la
+ propiedad.
+ </para>
+ </callout>
+ <callout arearefs="mappingcollection12">
+ <para>
+ <literal>optimistic-lock</literal> (opcional - por defecto a <literal>true</literal>):
+ Especifica que los cambios de estado de la colección resultan en
+ incrementos de versión de la entidad dueña. (Para asociaciones
+ uno a muchos, frecuentemente es razonable deshabilitar esta opción.)
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <sect2 id="collections-foreignkeys" >
+ <title>Claves foráneas de collección</title>
+
+ <para>
+ Las instancias de colección se distinguen en la base de datos por la
+ clave foránea de la entidad que posee la colección. Se hace
+ referencia a esta clave foránea como la <emphasis>columna clave de
+ colección</emphasis> (o columnas) de la tabla de colección.
+ La columna clave de la colección es mapeada por el elemento
+ <literal><key></literal>.
+ </para>
+
+ <para>
+ Puede haber una restricción de nulabilidad sobre la columna de clave
+ foránea. Para la mayoría de colecciones, esto está implicado.
+ Para asociaciones unidireccionales uno a muchos, la columna de clave
+ foránea es nulable por defecto, de modo que podrías necesitar
+ especificar <literal>not-null="true"</literal>.
+ </para>
+
+ <programlisting><![CDATA[<key column="productSerialNumber" not-null="true"/>]]></programlisting>
+
+ <para>
+ La restricción de clave foránea puede usar
+ <literal>ON DELETE CASCADE</literal>.
+ </para>
+
+ <programlisting><![CDATA[<key column="productSerialNumber" on-delete="cascade"/>]]></programlisting>
+
+ <para>
+ Mira el capítulo anterior por una definición completa del
+ elemento <literal><key></literal>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="collections-elements" >
+ <title>Elementos de collección</title>
+
+ <para>
+ Las colecciones pueden contener casi cualquier tipo de Hibernate, incluyendo
+ todos los tipos básicos, componentes, y por supuesto, referencias a otras
+ entidades. Esta es una distinción importante: un objeto en una colección
+ puede ser manejado con una semántica de "valor" (su ciclo de vida depende
+ completamente del propietario de la colección) o podría ser una referencia
+ a otra entidad, con su propio ciclo de vida. En el último caso, sólo
+ el estado del "enlace" entre los dos objetos se considera mantenido por la
+ colección.
+ </para>
+
+ <para>
+ Se hace referencia al tipo contenido como el <emphasis>tipo de elemento
+ de la colección</emphasis>. Los elementos de colección son
+ mapeados por <literal><element></literal> o
+ <literal><composite-element></literal>, o en el caso de referencias
+ de entidades, con <literal><one-to-many></literal> o
+ <literal><many-to-many></literal>. Las dos primeras mapean elementos
+ con semántica de valor, los dos siguientes son usados para mapear
+ asociaciones de entidades.
+ </para>
+
+ </sect2>
+
+ <sect2 id="collections-indexed">
+ <title>Colecciones indexadas</title>
+
+ <para>
+ Todos los mapeos de colección, excepto aquellos con semántica de
+ set o bag, necesitan una <emphasis>columna índice</emphasis> en la tabla
+ de colección, una columna que mapea a un índice de array, o
+ índice de <literal>List</literal>, o clave de <literal>Map</literal>.
+ El índice de un <literal>Map</literal> puede ser de cualquier tipo
+ básico, mapeado con <literal><map-key></literal>, o puede ser
+ una referencia de entidad, mapeada con <literal><map-key-many-to-many></literal>,
+ o puede ser un tipo compuesto, mapeado con <literal><composite-map-key></literal>.
+ El índice de un array o lista es siempre de tipo <literal>integer</literal>
+ y se mapea usando el elemento <literal><list-index></literal>. La columna
+ mapeada contiene enteros secuenciales (numerados desde cero, por defecto).
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="index1" coords="2 45"/>
+ <area id="index2" coords="3 45"/>
+ </areaspec>
+ <programlisting><![CDATA[<list-index
+ column="column_name"
+ base="0|1|..."/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="index1">
+ <para>
+ <literal>column_name</literal> (requerido): El nombre de la columna que tiene
+ los valores índice de la colección.
+ </para>
+ </callout>
+ <callout arearefs="index1">
+ <para>
+ <literal>base</literal> (opcional, por defecto a <literal>0</literal>): El valor
+ de la columna índice que corresponde al primer elemento de la lista o
+ array.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <programlistingco>
+ <areaspec>
+ <area id="mapkey1" coords="2 45"/>
+ <area id="mapkey2" coords="3 45"/>
+ <area id="mapkey3" coords="4 45"/>
+ </areaspec>
+ <programlisting><![CDATA[<map-key
+ column="column_name"
+ formula="any SQL expression"
+ type="type_name"
+ node="@attribute-name"
+ length="N"/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="mapkey1">
+ <para>
+ <literal>column</literal> (opcional): El nombre de la columna que tiene
+ los valores índice de la colección.
+ </para>
+ </callout>
+ <callout arearefs="mapkey2">
+ <para>
+ <literal>formula</literal> (opcional): Una fórmula SQL usada para
+ evaluar la clave del mapa.
+ </para>
+ </callout>
+ <callout arearefs="mapkey3">
+ <para>
+ <literal>type</literal> (requerido): el tipo de las claves del mapa.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <programlistingco>
+ <areaspec>
+ <area id="indexmanytomany1" coords="2 45"/>
+ <area id="indexmanytomany2" coords="3 45"/>
+ <area id="indexmanytomany3" coords="3 45"/>
+ </areaspec>
+ <programlisting><![CDATA[<map-key-many-to-many
+ column="column_name"
+ formula="any SQL expression"
+ class="ClassName"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="indexmanytomany1">
+ <para>
+ <literal>column</literal> (opcional): El nombre de la columna clave
+ foránea para los valores índice de la colección.
+ </para>
+ </callout>
+ <callout arearefs="indexmanytomany2">
+ <para>
+ <literal>formula</literal> (opcional): Una fórmula SQL usada para
+ evaluar la clave foránea de la clave del mapa.
+ </para>
+ </callout>
+ <callout arearefs="indexmanytomany3">
+ <para>
+ <literal>class</literal> (requerido): La clase de entidad usada como clave del mapa.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+
+ <para>
+ Si tu tabla no tiene una columna índice, y deseas aún usar <literal>List</literal> como
+ tipo de propiedad, debes mapear la propiedad como un <emphasis><bag></emphasis>
+ de Hibernate. Un bag (bolsa) no retiene su orden al ser recuperado de la base de datos,
+ pero puede ser ordenado o clasificado opcionalmente.
+ </para>
+
+ </sect2>
+
+ <para>
+ Hay absolutamente un rango de mapeos que pueden ser generados para colecciones,
+ cubriendo muchos modelos relacionales comunes. Te sugerimos que experimentes con
+ la herramienta de generación de esquemas para obtener una idea de cómo varias
+ declaraciones de mapeo se traducen a tablas de base de datos.
+ </para>
+
+ <sect2 id="collections-ofvalues" revision="1">
+ <title>Colecciones de valores y asociaciones muchos-a-muchos</title>
+
+ <para>
+ Cualquier colección de valores o asociación muchos a muchos requiere una
+ <emphasis>tabla de colección</emphasis> dedicada con una columna o columnas
+ de clave foránea, <emphasis>columna de elemento de colección</emphasis> o
+ columnas y posiblemente una columna o columnas índice.
+ </para>
+
+ <para>
+ Para una colección de valores, usamos la etiqueta <literal><element></literal>.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="element1b" coords="2 50"/>
+ <area id="element2b" coords="3 50"/>
+ <area id="element3b" coords="4 50"/>
+ </areaspec>
+ <programlisting><![CDATA[<element
+ column="column_name"
+ formula="any SQL expression"
+ type="typename"
+ length="L"
+ precision="P"
+ scale="S"
+ not-null="true|false"
+ unique="true|false"
+ node="element-name"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="element1b">
+ <para>
+ <literal>column</literal> (opcional): El nombre de la columna que tiene
+ los valores de los elementos de la colección.
+ </para>
+ </callout>
+ <callout arearefs="element2b">
+ <para>
+ <literal>formula</literal> (opcional): Una fórmula SQL usada para evaluar
+ el elemento.
+ </para>
+ </callout>
+ <callout arearefs="element3b">
+ <para>
+ <literal>type</literal> (requerido): El tipo del elemento de colección.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Una <emphasis>asociación muchos-a-muchos</emphasis> se especifica usando
+ el elemento <literal><many-to-many></literal>.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="manytomany1" coords="2 60"/>
+ <area id="manytomany2" coords="3 60"/>
+ <area id="manytomany3" coords="4 60"/>
+ <area id="manytomany4" coords="5 60"/>
+ <area id="manytomany5" coords="6 60"/>
+ <area id="manytomany6" coords="7 60"/>
+ <area id="manytomany7" coords="8 60"/>
+ </areaspec>
+ <programlisting><![CDATA[<many-to-many
+ column="column_name"
+ formula="any SQL expression"
+ class="ClassName"
+ fetch="select|join"
+ unique="true|false"
+ not-found="ignore|exception"
+ entity-name="EntityName"
+ node="element-name"
+ embed-xml="true|false"
+ />]]></programlisting>
+ <calloutlist>
+ <callout arearefs="manytomany1">
+ <para>
+ <literal>column</literal> (opcional): El nombre de la columna de clave
+ foránea del elemento.
+ </para>
+ </callout>
+ <callout arearefs="manytomany2">
+ <para>
+ <literal>formula</literal> (opcional): Una fórmula SQL opcional usada
+ para evaluar el valor de clave foránea del elemento.
+ </para>
+ </callout>
+ <callout arearefs="manytomany3">
+ <para>
+ <literal>class</literal> (requerido): El nombre de la clase asociada.
+ </para>
+ </callout>
+ <callout arearefs="manytomany4">
+ <para>
+ <literal>fetch</literal> (opcional - por defecto a <literal>join</literal>):
+ habilita la recuperación por unión externa o selección secuencial para esta
+ asociación. Este es un caso especial; para una recuperación completamente
+ temprana (en un solo <literal>SELECT</literal>) de una entidad y sus relaciones
+ muchos-a-muchos a otras entidades, deberías habilitar la recuperación
+ <literal>join</literal> no sólo de la colección misma, sino también con este
+ atributo en el elemento anidado <literal><many-to-many></literal>.
+ </para>
+ </callout>
+ <callout arearefs="manytomany5">
+ <para>
+ <literal>unique</literal> (opcional): Habilita la generación DDL de una
+ restricción de unicidad para la columna clave foránea. Esto hace la
+ multiplicidad de la asociación efectivamente uno a muchos.
+ </para>
+ </callout>
+ <callout arearefs="manytomany6">
+ <para>
+ <literal>not-found</literal> (opcional - por defecto a <literal>exception</literal>):
+ Especifica cómo serán manejadas las claves foráneas que referencian
+ filas perdidas: <literal>ignore</literal> tratará una fila perdida como
+ una asociación nula.
+ </para>
+ </callout>
+ <callout arearefs="manytomany7">
+ <para>
+ <literal>entity-name</literal> (opcional): El nombre de entidad de la clase
+ asociada, como una alternativa a <literal>class</literal>.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Algunos ejemplos, primero, un conjunto de cadenas:
+ </para>
+
+ <programlisting><![CDATA[<set name="names" table="person_names">
+ <key column="person_id"/>
+ <element column="person_name" type="string"/>
+</set>]]></programlisting>
+
+ <para>
+ Un bag conteniendo enteros (con un orden de iteración determinado por el
+ atributo <literal>order-by</literal>):
+ </para>
+
+ <programlisting><![CDATA[<bag name="sizes"
+ table="item_sizes"
+ order-by="size asc">
+ <key column="item_id"/>
+ <element column="size" type="integer"/>
+</bag>]]></programlisting>
+
+ <para>
+ Un array de entidades - en este caso, una asociación muchos a muchos:
+ </para>
+
+ <programlisting><![CDATA[<array name="addresses"
+ table="PersonAddress"
+ cascade="persist">
+ <key column="personId"/>
+ <list-index column="sortOrder"/>
+ <many-to-many column="addressId" class="Address"/>
+</array>]]></programlisting>
+
+ <para>
+ Un mapa de índices de cadenas a fechas:
+ </para>
+
+ <programlisting><![CDATA[<map name="holidays"
+ table="holidays"
+ schema="dbo"
+ order-by="hol_name asc">
+ <key column="id"/>
+ <map-key column="hol_name" type="string"/>
+ <element column="hol_date" type="date"/>
+</map>]]></programlisting>
+
+ <para>
+ Una lista de componentes (discutidos en el próximo capítulo):
+ </para>
+
+ <programlisting><![CDATA[<list name="carComponents"
+ table="CarComponents">
+ <key column="carId"/>
+ <list-index column="sortOrder"/>
+ <composite-element class="CarComponent">
+ <property name="price"/>
+ <property name="type"/>
+ <property name="serialNumber" column="serialNum"/>
+ </composite-element>
+</list>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="collections-onetomany">
+ <title>Asociaciones uno-a-muchos</title>
+
+ <para>
+ Una <emphasis>asociación uno a muchos</emphasis> enlaza las tablas de dos clases
+ por medio de una clave foránea, sin intervención de tabla de colección alguna.
+ Este mapeo pierde cierta semántica de colecciones Java normales:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Una instancia de la clase entidad contenida no puede pertenecer
+ a más de una instancia de la colección.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Una instancia de la clase entidad contenida no puede aparecer en más
+ de un valor del índice de colección.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Una asociación de <literal>Product</literal> a <literal>Part</literal> requiere la
+ existencia de una columna clave foránea y posiblemente una columna índice a la tabla
+ <literal>Part</literal>. Una etiqueta <literal><one-to-many></literal> indica
+ que ésta es una asociación uno a muchos.
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="onetomany1" coords="2 60"/>
+ <area id="onetomany2" coords="3 60"/>
+ <area id="onetomany3" coords="4 60"/>
+ </areaspec>
+ <programlisting><![CDATA[<one-to-many
+ class="ClassName"
+ not-found="ignore|exception"
+ entity-name="EntityName"
+ node="element-name"
+ embed-xml="true|false"
+ />]]></programlisting>
+ <calloutlist>
+ <callout arearefs="onetomany1">
+ <para>
+ <literal>class</literal> (requerido): El nombre de la clase asociada.
+ </para>
+ </callout>
+ <callout arearefs="onetomany2">
+ <para>
+ <literal>not-found</literal> (opcional - por defecto a <literal>exception</literal>):
+ Especifica cómo serán manejados los identificadores en caché que referencien
+ filas perdidas: <literal>ignore</literal> tratará una fila perdida como una
+ asociación nula.
+ </para>
+ </callout>
+ <callout arearefs="onetomany3">
+ <para>
+ <literal>entity-name</literal> (opcional): El nombre de entidad de la clase
+ asociada, como una alternativa a <literal>class</literal>.
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Observa que el elemento <literal><one-to-many></literal> no necesita
+ declarar ninguna columna. Ni es necesario especificar el nombre de <literal>table</literal>
+ en ningún sitio.
+ </para>
+
+ <para>
+ <emphasis>Nota muy importante:</emphasis> Si la columna clave foránea de una asociación
+ <literal><one-to-many></literal> es declarada <literal>NOT NULL</literal>, debes
+ declarar el mapeo de <literal><key></literal> <literal>not-null="true"</literal>
+ o <emphasis>usar una asociación bidireccional</emphasis> con el mapeo de colección
+ marcado <literal>inverse="true"</literal>. Ver la discusión sobre asociaciones
+ bidireccionales más adelante en este capítulo.
+ </para>
+
+ <para>
+ Este ejemplo muestra un mapa de entidades <literal>Part</literal> por nombre
+ (donde <literal>partName</literal> es una propiedad persistente de <literal>Part</literal>).
+ Observa el uso de un índice basado en fórmula.
+ </para>
+
+ <programlisting><![CDATA[<map name="parts"
+ cascade="all">
+ <key column="productId" not-null="true"/>
+ <map-key formula="partName"/>
+ <one-to-many class="Part"/>
+</map>]]></programlisting>
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="collections-advancedmappings">
+ <title>Mapeos de colección avanzados</title>
+
+ <sect2 id="collections-sorted" revision="2">
+ <title>Colecciones ordenadas</title>
+
+ <para>
+ Hibernate soporta colecciones implementando <literal>java.util.SortedMap</literal> y
+ <literal>java.util.SortedSet</literal>. Debes especificar un comparador en el fichero de
+ mapeo:
+ </para>
+
+ <programlisting><![CDATA[<set name="aliases"
+ table="person_aliases"
+ sort="natural">
+ <key column="person"/>
+ <element column="name" type="string"/>
+</set>
+
+<map name="holidays" sort="my.custom.HolidayComparator">
+ <key column="year_id"/>
+ <map-key column="hol_name" type="string"/>
+ <element column="hol_date" type="date"/>
+</map>]]></programlisting>
+
+ <para>
+ Los valores permitidos del atributo <literal>sort</literal> son <literal>unsorted</literal>,
+ <literal>natural</literal> y el nombre de una clase que implemente
+ <literal>java.util.Comparator</literal>.
+ </para>
+
+ <para>
+ Las colecciones ordenadas realmente se comportan como <literal>java.util.TreeSet</literal> o
+ <literal>java.util.TreeMap</literal>.
+ </para>
+
+ <para>
+ Si quieres que la misma base de datos ordene los elementos de colección usa el
+ atributo <literal>order-by</literal> de los mapeos <literal>set</literal>,
+ <literal>bag</literal> o <literal>map</literal>. Esta solución está disponible sólo
+ bajo el JDK 1.4 o superior (está implementado usando <literal>LinkedHashSet</literal> o
+ <literal>LinkedHashMap</literal>). Esto realiza la ordenación en la consulta SQL,
+ no en memoria.
+ </para>
+
+ <programlisting><![CDATA[<set name="aliases" table="person_aliases" order-by="lower(name) asc">
+ <key column="person"/>
+ <element column="name" type="string"/>
+</set>
+
+<map name="holidays" order-by="hol_date, hol_name">
+ <key column="year_id"/>
+ <map-key column="hol_name" type="string"/>
+ <element column="hol_date type="date"/>
+</map>]]></programlisting>
+
+ <para>
+ Observa que el valor del atributo <literal>order-by</literal> es una ordenación SQL, no
+ una ordenación HQL!
+ </para>
+
+ <para>
+ Las asociaciones pueden incluso ser ordenadas por algún criterio arbitrario en tiempo de
+ ejecución usando un <literal>filter()</literal> de colección.
+ </para>
+
+ <programlisting><![CDATA[sortedUsers = s.createFilter( group.getUsers(), "order by this.name" ).list();]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="collections-bidirectional" revision="1">
+ <title>Asociaciones bidireccionales</title>
+
+ <para>
+ Una <emphasis>asociación bidireccional</emphasis> permite la nevegación desde
+ ambos "extremos" de la asociación. Son soportados dos tipos de asociación
+ bidireccional:
+
+ <variablelist>
+ <varlistentry>
+ <term>uno-a-muchos</term>
+ <listitem>
+ <para>
+ set o bag valorados en un extremo, monovaluados al otro
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>muchos-a-muchos</term>
+ <listitem>
+ <para>
+ set o bag valorados a ambos extremos
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ </para>
+
+ <para>
+ Puedes especificar una asociación bidireccional muchos-a-muchos simplemente
+ mapeando dos asociaciones muchos-a-muchos a la misma tabla de base de datos
+ y declarando un extremo como <emphasis>inverse</emphasis> (cuál de ellos es tu
+ elección, pero no puede ser una colección indexada).
+ </para>
+
+ <para>
+ He aquí un ejemplo de una asociación bidireccional muchos-a-muchos; cada categoría
+ puede tener muchos ítems y cada ítem puede estar en muchas categorías:
+ </para>
+
+ <programlisting><![CDATA[<class name="Category">
+ <id name="id" column="CATEGORY_ID"/>
+ ...
+ <bag name="items" table="CATEGORY_ITEM">
+ <key column="CATEGORY_ID"/>
+ <many-to-many class="Item" column="ITEM_ID"/>
+ </bag>
+</class>
+
+<class name="Item">
+ <id name="id" column="ITEM_ID"/>
+ ...
+
+ <!-- inverse end -->
+ <bag name="categories" table="CATEGORY_ITEM" inverse="true">
+ <key column="ITEM_ID"/>
+ <many-to-many class="Category" column="CATEGORY_ID"/>
+ </bag>
+</class>]]></programlisting>
+
+ <para>
+ Los cambios hechos sólo al extremo inverso de la asociación <emphasis>no</emphasis>
+ son persistidos. Esto significa que Hibernate tiene dos representaciones en memoria
+ para cada asociación bidireccional, una enlaza de A a B y otra enlaza de B a A.
+ Esto es más fácil de entender si piensas en el modelo de objetos de Java y cómo
+ creamos una relación muchos-a-muchos en Java:
+ </para>
+
+ <programlisting><![CDATA[
+category.getItems().add(item); // The category now "knows" about the relationship
+item.getCategories().add(category); // The item now "knows" about the relationship
+
+session.persist(item); // The relationship won't be saved!
+session.persist(category); // The relationship will be saved]]></programlisting>
+
+ <para>
+ El lado no-inverso se usa para salvar la representación en memoria a la base de datos.
+ </para>
+
+ <para>
+ Puedes definir una asociación bidireccional uno-a-muchos mapeando una asociación uno-a-muchos
+ a la misma columna (o columnas) de tabla como una asociación muchos-a-uno y declarando el
+ extremo multivaluado <literal>inverse="true"</literal>.
+ </para>
+
+ <programlisting><![CDATA[<class name="Parent">
+ <id name="id" column="parent_id"/>
+ ....
+ <set name="children" inverse="true">
+ <key column="parent_id"/>
+ <one-to-many class="Child"/>
+ </set>
+</class>
+
+<class name="eg.Child">
+ <id name="id" column="id"/>
+ ....
+ <many-to-one name="parent"
+ class="Parent"
+ column="parent_id"
+ not-null="true"/>
+</class>]]></programlisting>
+
+ <para>
+ Mapear un extremo de una asociación con <literal>inverse="true"</literal> no afecta
+ la operación de cascadas; éstos son conceptos ortogonales!
+ </para>
+
+ </sect2>
+
+ <sect2 id="collections-indexedbidirectional">
+ <title>Asociaciones bidireccionales con colecciones indexadas</title>
+ <para>
+ Requiere especial consideración una asociación bidireccional donde un extremo esté representado
+ como una <literal><list></literal> o <literal><map></literal>. Si hay una propiedad
+ de la clase hija que mapee a la columna índice, no hay problema, podemos seguir usando
+ <literal>inverse="true"</literal> en el mapeo de la colección:
+ </para>
+
+ <programlisting><![CDATA[<class name="Parent">
+ <id name="id" column="parent_id"/>
+ ....
+ <map name="children" inverse="true">
+ <key column="parent_id"/>
+ <map-key column="name"
+ type="string"/>
+ <one-to-many class="Child"/>
+ </map>
+</class>
+
+<class name="Child">
+ <id name="id" column="child_id"/>
+ ....
+ <property name="name"
+ not-null="true"/>
+ <many-to-one name="parent"
+ class="Parent"
+ column="parent_id"
+ not-null="true"/>
+</class>]]></programlisting>
+
+ <para>
+ Pero, si no existe tal proiedad en la clase hija, no podemos pensar en la asociación como
+ verdaderamente bidireccional (hay información en un extremo de la asociación que no está
+ disponible en el otro extremo). En este caso, no podemos mapear la colección con
+ <literal>inverse="true"</literal>. En cambio, podríamos usar el siguiente mapeo:
+ </para>
+
+ <programlisting><![CDATA[<class name="Parent">
+ <id name="id" column="parent_id"/>
+ ....
+ <map name="children">
+ <key column="parent_id"
+ not-null="true"/>
+ <map-key column="name"
+ type="string"/>
+ <one-to-many class="Child"/>
+ </map>
+</class>
+
+<class name="Child">
+ <id name="id" column="child_id"/>
+ ....
+ <many-to-one name="parent"
+ class="Parent"
+ column="parent_id"
+ insert="false"
+ update="false"
+ not-null="true"/>
+</class>]]></programlisting>
+
+ <para>
+ Nota que, en este mapeo, el extremo de la asociación valuado en colección es responsable de las
+ actualizaciones a la clave foránea.
+ </para>
+
+ </sect2>
+
+ <sect2 id="collections-ternary">
+ <title>Asociaciones ternarias</title>
+
+ <para>
+ Hay tres enfoques posibles para mapear una asociación ternaria.
+ Una es usar un <literal>Map</literal> con una asociación como su índice:
+ </para>
+
+ <programlisting><![CDATA[<map name="contracts">
+ <key column="employer_id" not-null="true"/>
+ <map-key-many-to-many column="employee_id" class="Employee"/>
+ <one-to-many class="Contract"/>
+</map>]]></programlisting>
+
+ <programlisting><![CDATA[<map name="connections">
+ <key column="incoming_node_id"/>
+ <map-key-many-to-many column="outgoing_node_id" class="Node"/>
+ <many-to-many column="connection_id" class="Connection"/>
+</map>]]></programlisting>
+
+ <para>
+ Un segundo enfoque es simplemente remodelar la asociación como una clase de entidad.
+ Este es el enfoque que usamos más comunmente.
+ </para>
+
+ <para>
+ Una alternativa final es usar elementos compuestos, que discutiremos más adelante.
+ </para>
+
+ </sect2>
+
+ <sect2 id="collections-idbag" revision="1">
+ <title><literal>Usando un <idbag></literal></title>
+
+ <para>
+ Si has adoptado completamente nuestra visión de que las claves compuestas son una
+ cosa mala y que las entidades deben tener identificadores sitéticos (claves delegadas),
+ entonces podrías encontrar un poco raro que todas las asociaciones muchos a muchos y
+ las colecciones de valores que hemos mostrado hasta ahora mapeen a tablas con claves
+ compuestas! Ahora, este punto es discutible; una tabla de pura asociación no parece
+ beneficiarse demasiado de una clave delegada (aunque sí <emphasis>podría</emphasis> una
+ colección de valores compuestos). Sin embargo, Hibernate provee una funcionalidad que
+ te permite mapear asociaciones muchos a muchos y colecciones de valores a una tabla con
+ una clave delegada.
+ </para>
+
+ <para>
+ El elemento <literal><idbag></literal> te permite mapear una <literal>List</literal>
+ (o <literal>Collection</literal>) con semántica de bag.
+ </para>
+
+<programlisting><![CDATA[<idbag name="lovers" table="LOVERS">
+ <collection-id column="ID" type="long">
+ <generator class="sequence"/>
+ </collection-id>
+ <key column="PERSON1"/>
+ <many-to-many column="PERSON2" class="Person" fetch="join"/>
+</idbag>]]></programlisting>
+
+ <para>
+ Como puedes ver, un <literal><idbag></literal> tiene un generador de id sintético,
+ igual que una clase de entidad! Una clave delegada diferente se asigna a cada fila
+ de la colección. Hibernate no provee ningún mecanismo para descubrir el valor de clave
+ delegada de una fila en particular, sin embargo.
+ </para>
+
+ <para>
+ Observa que el rendimiento de actualización de un <literal><idbag></literal> es
+ <emphasis>mucho</emphasis> mejor que el de un <literal><bag></literal> regular!
+ Hibernate puede localizar filas individuales eficientemente y actualizarlas o borrarlas
+ individualmente, igual que si fuese una lista, mapa o conjunto.
+ </para>
+
+ <para>
+ En la implementación actual, la estrategia de generación de identificador
+ <literal>native</literal> no está soportada para identificadores de colecciones
+ <literal><idbag></literal>.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <!--undocumenting this stuff -->
+
+ <!--sect1 id="collections-heterogeneous">
+ <title>Heterogeneous Associations</title>
+
+ <para>
+ The <literal><many-to-any></literal> and <literal><index-many-to-any></literal>
+ elements provide for true heterogeneous associations. These mapping elements work in the
+ same way as the <literal><any></literal> element - and should also be used
+ rarely, if ever.
+ </para>
+
+ </sect1-->
+
+ <sect1 id="collections-example" revision="1">
+ <title>Ejemplos de colección</title>
+
+ <para>
+ Las secciones previas son bastantes confusas. Así que miremos un ejemplo.
+ Esta clase:
+ </para>
+
+ <programlisting><![CDATA[package eg;
+import java.util.Set;
+
+public class Parent {
+ private long id;
+ private Set children;
+
+ public long getId() { return id; }
+ private void setId(long id) { this.id=id; }
+
+ private Set getChildren() { return children; }
+ private void setChildren(Set children) { this.children=children; }
+
+ ....
+ ....
+}]]></programlisting>
+
+ <para>
+ tiene una colección de instancias de <literal>Child</literal>.
+ Si cada hijo tiene como mucho un padre, el mapeo más natural es
+ una asociación uno-a-muchos:
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Parent">
+ <id name="id">
+ <generator class="sequence"/>
+ </id>
+ <set name="children">
+ <key column="parent_id"/>
+ <one-to-many class="Child"/>
+ </set>
+ </class>
+
+ <class name="Child">
+ <id name="id">
+ <generator class="sequence"/>
+ </id>
+ <property name="name"/>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Esto mapea a las siguientes definiciones de tablas:
+ </para>
+
+ <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null primary key, name varchar(255), parent_id bigint )
+alter table child add constraint childfk0 (parent_id) references parent]]></programlisting>
+
+ <para>
+ Si el padre es <emphasis>requerido</emphasis>, usa una asociación bidireccional
+ uno-a-muchos:
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Parent">
+ <id name="id">
+ <generator class="sequence"/>
+ </id>
+ <set name="children" inverse="true">
+ <key column="parent_id"/>
+ <one-to-many class="Child"/>
+ </set>
+ </class>
+
+ <class name="Child">
+ <id name="id">
+ <generator class="sequence"/>
+ </id>
+ <property name="name"/>
+ <many-to-one name="parent" class="Parent" column="parent_id" not-null="true"/>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Observa la restricción <literal>NOT NULL</literal>:
+ </para>
+
+ <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null
+ primary key,
+ name varchar(255),
+ parent_id bigint not null )
+alter table child add constraint childfk0 (parent_id) references parent]]></programlisting>
+
+ <para>
+ Alternativamente, si absolutamente insistes que esta asociación debe ser unidireccional,
+ puedes declarar la restricción <literal>NOT NULL</literal> en el mapeo de
+ <literal><key></literal>:
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Parent">
+ <id name="id">
+ <generator class="sequence"/>
+ </id>
+ <set name="children">
+ <key column="parent_id" not-null="true"/>
+ <one-to-many class="Child"/>
+ </set>
+ </class>
+
+ <class name="Child">
+ <id name="id">
+ <generator class="sequence"/>
+ </id>
+ <property name="name"/>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ En la otra mano, si un hijo pudiera tener múltiples padres, sería apropiada
+ una asociación muchos-a-muchos:
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Parent">
+ <id name="id">
+ <generator class="sequence"/>
+ </id>
+ <set name="children" table="childset">
+ <key column="parent_id"/>
+ <many-to-many class="Child" column="child_id"/>
+ </set>
+ </class>
+
+ <class name="Child">
+ <id name="id">
+ <generator class="sequence"/>
+ </id>
+ <property name="name"/>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Definiciones de tabla:
+ </para>
+
+ <programlisting><![CDATA[create table parent ( id bigint not null primary key )
+create table child ( id bigint not null primary key, name varchar(255) )
+create table childset ( parent_id bigint not null,
+ child_id bigint not null,
+ primary key ( parent_id, child_id ) )
+alter table childset add constraint childsetfk0 (parent_id) references parent
+alter table childset add constraint childsetfk1 (child_id) references child]]></programlisting>
+
+ <para>
+ Para más ejemplos y un paseo completo a través del mapeo de relaciones padre/hijo,
+ ver <xref linkend="example-parentchild"/>.
+ </para>
+
+ <para>
+ Son posibles mapeos de asociación aún más complejos. Catalogaremos todas las posibilidades
+ en el próximo capítulo.
+ </para>
+
+ </sect1>
+
+</chapter>
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/content/component_mapping.xml (from rev 12794, core/trunk/documentation/manual/es-ES/src/main/docbook/modules/component_mapping.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/component_mapping.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/component_mapping.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,403 @@
+<chapter id="components">
+ <title>Mapeo de Componentes</title>
+
+ <para>
+ La noción de un <emphasis>componente</emphasis> es reusada en muchos contextos diferentes,
+ para propósitos diferentes, a través de Hibernate.
+ </para>
+
+ <sect1 id="components-dependentobjects">
+ <title>Objetos dependientes</title>
+
+ <para>
+ Un componente es un objeto contenido que es persistido como un tipo de valor, no una
+ referencia de entidad. El término "componente" hace referencia a la noción orientada a
+ objetos de composición (no a componentes a nivel de arquitectura). Por ejemplo, podrías
+ modelar una persona como:
+ </para>
+
+ <programlisting><![CDATA[public class Person {
+ private java.util.Date birthday;
+ private Name name;
+ private String key;
+ public String getKey() {
+ return key;
+ }
+ private void setKey(String key) {
+ this.key=key;
+ }
+ public java.util.Date getBirthday() {
+ return birthday;
+ }
+ public void setBirthday(java.util.Date birthday) {
+ this.birthday = birthday;
+ }
+ public Name getName() {
+ return name;
+ }
+ public void setName(Name name) {
+ this.name = name;
+ }
+ ......
+ ......
+}]]></programlisting>
+
+<programlisting><![CDATA[public class Name {
+ char initial;
+ String first;
+ String last;
+ public String getFirst() {
+ return first;
+ }
+ void setFirst(String first) {
+ this.first = first;
+ }
+ public String getLast() {
+ return last;
+ }
+ void setLast(String last) {
+ this.last = last;
+ }
+ public char getInitial() {
+ return initial;
+ }
+ void setInitial(char initial) {
+ this.initial = initial;
+ }
+}]]></programlisting>
+
+ <para>
+ Ahora <literal>Name</literal> puede ser persistido como un componente de
+ <literal>Person</literal>. Observa que <literal>Name</literal> define métodos
+ getter y setter para sus propiedades persistentes, pero no necesita declarar
+ ninguna interface ni propiedades identificadoras.
+ </para>
+
+ <para>
+ Nuestro mapeo de Hibernate se vería así:
+ </para>
+
+ <programlisting><![CDATA[<class name="eg.Person" table="person">
+ <id name="Key" column="pid" type="string">
+ <generator class="uuid.hex"/>
+ </id>
+ <property name="birthday" type="date"/>
+ <component name="Name" class="eg.Name"> <!-- class attribute optional -->
+ <property name="initial"/>
+ <property name="first"/>
+ <property name="last"/>
+ </component>
+</class>]]></programlisting>
+
+ <para>
+ La tabla person tendría las columnas <literal>pid</literal>,
+ <literal>birthday</literal>,
+ <literal>initial</literal>,
+ <literal>first</literal> y
+ <literal>last</literal>.
+ </para>
+
+ <para>
+ Como todos los tipos de valor, los componentes no soportan referencias compartidas.
+ En otras palabras, dos personas pueden tener el mismo nombre, pero los dos objetos
+ persona contendrían dos objetos nombre independientes, sólo "iguales" en valor.
+ La semántica de valor nulo de un componente es <emphasis>ad hoc</emphasis>.
+ Cuando se recargue el objeto contenedor, Hibernate asumirá que si todas las columnas del
+ componente son nulas, el componente entero es nulo. Esto debe estar bien para la mayoría
+ de propósitos.
+ </para>
+
+ <para>
+ Las propiedades de un componentes pueden ser de cualquier tipo de Hibernate
+ (colecciones, muchos-a-uno, asociaciones, otros componentes, etc). Los componentes
+ anidados <emphasis>no</emphasis> deben ser considerados un uso exótico. Hibernate está
+ concebido para soportar un modelo de objetos granularizado en fino.
+ </para>
+
+ <para>
+ El elemento <literal><component></literal> permite un subelemento
+ <literal><parent></literal> que mapee una propiedad de la clase del componente
+ como una referencia de regreso a la entidad contenedora.
+ </para>
+
+ <programlisting><![CDATA[<class name="eg.Person" table="person">
+ <id name="Key" column="pid" type="string">
+ <generator class="uuid.hex"/>
+ </id>
+ <property name="birthday" type="date"/>
+ <component name="Name" class="eg.Name" unique="true">
+ <parent name="namedPerson"/> <!-- reference back to the Person -->
+ <property name="initial"/>
+ <property name="first"/>
+ <property name="last"/>
+ </component>
+</class>]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="components-incollections" revision="1">
+ <title>Colecciones de objetos dependientes</title>
+
+ <para>
+ Las colecciones de componentes están soportadas (por ejemplo,
+ un array de tipo <literal>Name</literal>). Declara tu colección
+ de componentes remplazando la etiqueta <literal><element></literal>
+ por una etiqueta <literal><composite-element></literal>.
+ </para>
+
+ <programlisting><![CDATA[<set name="someNames" table="some_names" lazy="true">
+ <key column="id"/>
+ <composite-element class="eg.Name"> <!-- class attribute required -->
+ <property name="initial"/>
+ <property name="first"/>
+ <property name="last"/>
+ </composite-element>
+</set>]]></programlisting>
+
+ <para>
+ Nota: si defines un <literal>Set</literal> de elementos compuestos, es muy
+ importante implementar <literal>equals()</literal> y <literal>hashCode()</literal>
+ correctamente.
+ </para>
+
+ <para>
+ Los elementos compuestos pueden contener componentes pero no colecciones.
+ Si tu elemento compuesto contiene a su vez componentes, usa la etiqueta
+ <literal><nested-composite-element></literal>. Este es un caso bastante
+ exótico - una colección de componentes que a su vez tienen componentes. A esta
+ altura debes estar preguntándote si una asociación uno-a-muchos es más
+ apropiada. Intenta remodelar el elemento compuesto como una entidad - pero
+ observa que aunque el modelo Java es el mismo, el modelo relacional y la
+ semántica de persistencia siguen siendo ligeramente diferentes.
+ </para>
+
+ <para>
+ Por favor observa que un mapeo de elemento compuesto no soporta
+ propiedades nulables si estás usando un <literal><set></literal>.
+ Hibernate tiene que usar cada columna para identificar un registro
+ al borrar objetos (no hay una columna clave primaria separada en la tabla del
+ elemento compuesto), lo que es imposible con valores nulos. Tienes que, o bien usar
+ sólo propiedades no nulas en un elemento compuesto o elegir un
+ <literal><list></literal>, <literal><map></literal>,
+ <literal><bag></literal> o <literal><idbag></literal>.
+ </para>
+
+ <para>
+ Un caso especial de un elemento compuesto es un elemento compuesto con un
+ elemento anidado <literal><many-to-one></literal>. Un mapeo como este
+ te permite mapear columnas extra de una tabla de asociación muchos-a-muchos
+ a la clase del elemento compuesto. La siguiente es una asociación muchos-a-muchos
+ de <literal>Order</literal> a <literal>Item</literal> donde
+ <literal>purchaseDate</literal>, <literal>price</literal> y
+ <literal>quantity</literal> son propiedades de la asociación:
+ </para>
+
+ <programlisting><![CDATA[<class name="eg.Order" .... >
+ ....
+ <set name="purchasedItems" table="purchase_items" lazy="true">
+ <key column="order_id">
+ <composite-element class="eg.Purchase">
+ <property name="purchaseDate"/>
+ <property name="price"/>
+ <property name="quantity"/>
+ <many-to-one name="item" class="eg.Item"/> <!-- class attribute is optional -->
+ </composite-element>
+ </set>
+</class>]]></programlisting>
+
+ <para>
+ Por supuesto, no puede haber una referencia a la compra del otro lado para la
+ navegación bidireccional de la asociación. Recuerda que los componentes son tipos de
+ valor no permiten referencias compartidas. Una sola <literal>Purchase</literal> puede
+ estar en el conjunto de una <literal>Order</literal>, pero no puede ser referenciada
+ por el <literal>Item</literal> al mismo tiempo.
+ </para>
+
+ <para>Incluso son posibles las asociaciones ternarias (o cuaternarias, etc):</para>
+
+ <programlisting><![CDATA[<class name="eg.Order" .... >
+ ....
+ <set name="purchasedItems" table="purchase_items" lazy="true">
+ <key column="order_id">
+ <composite-element class="eg.OrderLine">
+ <many-to-one name="purchaseDetails class="eg.Purchase"/>
+ <many-to-one name="item" class="eg.Item"/>
+ </composite-element>
+ </set>
+</class>]]></programlisting>
+
+ <para>
+ Los elementos compuestos pueden aparecer en consultas usando la misma
+ sintáxis que las asociaciones a otras entidades.
+ </para>
+
+ </sect1>
+
+ <sect1 id="components-asmapindex">
+ <title>Componentes como índices de Map</title>
+
+ <para>
+ El elemento <literal><composite-map-key></literal> te permite mapear
+ una clase componente como la clave de un <literal>Map</literal>. Asegúrate que
+ sobrescribes <literal>hashCode()</literal> y <literal>equals()</literal>
+ correctamente en la clase componente.
+ </para>
+ </sect1>
+
+ <sect1 id="components-compositeid" revision="1">
+ <title>Componentes como identificadores compuestos</title>
+
+ <para>
+ Puedes usar un componente como un identidicador de una clase entidad. Tu clase
+ componente debe satisfacer ciertos requerimientos:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Debe implementar <literal>java.io.Serializable</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Debe re-implementar <literal>equals()</literal> y
+ <literal>hashCode()</literal>, consistentemente con la
+ noción de base de datos de igualdad de clave compuesta.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ <emphasis>Nota: en Hibernat3, el segundo requerimiento no es absolutamente un
+ requerimiento rígido de Hibernate. Pero de todas formas, házlo.</emphasis>
+ </para>
+
+ <para>
+ No puedes usar un <literal>IdentifierGenerator</literal> para generar claves
+ compuestas. La aplicación debe, en cambio, asignar sus propios identificadores.
+ </para>
+
+ <para>
+ Usa la etiqueta <literal><composite-id></literal> (con elementos
+ anidados <literal><key-property></literal>) en lugar de la usual
+ declaración <literal><id></literal>. Por ejemplo, la clase
+ <literal>OrderLine</literal> tiene una clave primaria que depende de
+ la clave primaria (compuesta) de <literal>Order</literal>.
+ </para>
+
+ <programlisting><![CDATA[<class name="OrderLine">
+
+ <composite-id name="id" class="OrderLineId">
+ <key-property name="lineId"/>
+ <key-property name="orderId"/>
+ <key-property name="customerId"/>
+ </composite-id>
+
+ <property name="name"/>
+
+ <many-to-one name="order" class="Order"
+ insert="false" update="false">
+ <column name="orderId"/>
+ <column name="customerId"/>
+ </many-to-one>
+ ....
+
+</class>]]></programlisting>
+
+ <para>
+ Ahora, cualquier clave foránea que referencie la tabla de <literal>OrderLine</literal>
+ es también compuesta. Debes declarar esto en tus mapeos de otras clases. Una asociación
+ a <literal>OrderLine</literal> sería mapeado así:
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="orderLine" class="OrderLine">
+<!-- the "class" attribute is optional, as usual -->
+ <column name="lineId"/>
+ <column name="orderId"/>
+ <column name="customerId"/>
+</many-to-one>]]></programlisting>
+
+ <para>
+ (Nota que la etiqueta <literal><column></literal> es una alternativa al
+ atributo <literal>column</literal> en cualquier sitio.)
+ </para>
+
+ <para>
+ Una asociación <literal>muchos-a-muchos</literal> a <literal>OrderLine</literal>
+ también usa la clave foránea compuesta:
+ </para>
+
+ <programlisting><![CDATA[<set name="undeliveredOrderLines">
+ <key column name="warehouseId"/>
+ <many-to-many class="OrderLine">
+ <column name="lineId"/>
+ <column name="orderId"/>
+ <column name="customerId"/>
+ </many-to-many>
+</set>]]></programlisting>
+
+ <para>
+ La colección de <literal>OrderLine</literal>s en <literal>Order</literal> usaría:
+ </para>
+
+ <programlisting><![CDATA[<set name="orderLines" inverse="true">
+ <key>
+ <column name="orderId"/>
+ <column name="customerId"/>
+ </key>
+ <one-to-many class="OrderLine"/>
+</set>]]></programlisting>
+
+ <para>
+ (El elemento <literal><one-to-many></literal>, como es usual, no declara columnas.)
+ </para>
+
+ <para>
+ Si <literal>OrderLine</literal> posee una colección por sí misma, tiene también
+ una clave foránea compuesta.
+ </para>
+
+ <programlisting><![CDATA[<class name="OrderLine">
+ ....
+ ....
+ <list name="deliveryAttempts">
+ <key> <!-- a collection inherits the composite key type -->
+ <column name="lineId"/>
+ <column name="orderId"/>
+ <column name="customerId"/>
+ </key>
+ <list-index column="attemptId" base="1"/>
+ <composite-element class="DeliveryAttempt">
+ ...
+ </composite-element>
+ </set>
+</class>]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="components-dynamic" revision="1">
+ <title>Componentes dinámicos</title>
+
+ <para>
+ Puedes incluso mapear una propiedad de tipo <literal>Map</literal>:
+ </para>
+
+ <programlisting><![CDATA[<dynamic-component name="userAttributes">
+ <property name="foo" column="FOO" type="string"/>
+ <property name="bar" column="BAR" type="integer"/>
+ <many-to-one name="baz" class="Baz" column="BAZ_ID"/>
+</dynamic-component>]]></programlisting>
+
+ <para>
+ La semántica de un mapeo <literal><dynamic-component></literal> es ídentica
+ a la de <literal><component></literal>. La ventaja de este tipo de mapeos es
+ la habilidad para determinar las propiedades reales del bean en tiempo de despliegue,
+ sólo con editar el documento de mapeo. La manipulación del documento de mapeo en tiempo
+ de ejecución es también posible, usando un analizador DOM. Incluso mejor, puedes acceder
+ (y cambiar) el metamodelo de tiempo de configuración de Hibernate por medio del objeto
+ <literal>Configuration</literal>.
+ </para>
+
+ </sect1>
+
+</chapter>
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/content/configuration.xml (from rev 12794, core/trunk/documentation/manual/es-ES/src/main/docbook/modules/configuration.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/configuration.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/configuration.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,1761 @@
+<chapter id="session-configuration" revision="1">
+
+ <title>Configuración</title>
+
+ <para>
+ Debido a que Hibernate está diseñado para operar en muchos entornos
+ diferentes, hay un gran número de parámetros de configuración.
+ Afortunadamente, la mayoría tiene valores por defecto sensibles e Hibernate
+ se distribuye con un fichero <literal>hibernate.properties</literal> de ejemplo en
+ <literal>etc/</literal> que muestra las diversas opciones. Tan sólo pon el
+ fichero de ejemplo en tu classpath y personalízalo.
+ </para>
+
+ <sect1 id="configuration-programmatic" revision="1">
+ <title>Configuración programática</title>
+
+ <para>
+ Una instancia de <literal>org.hibernate.cfg.Configuration</literal>
+ representa un conjunto entero de mapeos de los tipos Java de una aplicación
+ a una base de datos SQL. La <literal>Configuration</literal> es usada para
+ construir una <literal>SessionFactory</literal> (inmutable). Los mapeos se
+ compilan de varios ficheros de mapeo XML.
+ </para>
+
+ <para>
+ Puedes obtener una instancia de <literal>Configuration</literal> instanciándola
+ directamente y especificando documentos de mapeo XML. Si los ficheros de mapeo
+ están en el classpath, usa <literal>addResource()</literal>:
+ </para>
+
+ <programlisting><![CDATA[Configuration cfg = new Configuration()
+ .addResource("Item.hbm.xml")
+ .addResource("Bid.hbm.xml");]]></programlisting>
+
+ <para>
+ Una forma alternativa (a veces mejor) es especificar la clase mapeada,
+ y dejar que Hibernate encuentre el documento de mapeo por ti:
+ </para>
+
+ <programlisting><![CDATA[Configuration cfg = new Configuration()
+ .addClass(org.hibernate.auction.Item.class)
+ .addClass(org.hibernate.auction.Bid.class);]]></programlisting>
+
+ <para>
+ Entonces Hibernate buscará ficheros de mapeo llamados
+ <literal>/org/hibernate/auction/Item.hbm.xml</literal> y
+ <literal>/org/hibernate/auction/Bid.hbm.xml</literal> en el classpath.
+ Este enfoque elimina cualquier nombre de fichero en el código.
+ </para>
+
+ <para>
+ Una <literal>Configuration</literal> también te permite especificar
+ propiedades de configuración:
+ </para>
+
+ <programlisting><![CDATA[Configuration cfg = new Configuration()
+ .addClass(org.hibernate.auction.Item.class)
+ .addClass(org.hibernate.auction.Bid.class)
+ .setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect")
+ .setProperty("hibernate.connection.datasource", "java:comp/env/jdbc/test")
+ .setProperty("hibernate.order_updates", "true");]]></programlisting>
+
+ <para>
+ Esta no es la única forma de pasar propiedades de configuración
+ a Hibernate. La diversas opciones incluyen:
+ </para>
+
+ <orderedlist spacing="compact">
+ <listitem>
+ <para>
+ Pasar una instancia de <literal>java.util.Properties</literal> a
+ <literal>Configuration.setProperties()</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Colocar <literal>hibernate.properties</literal> en un directorio
+ raíz del classpath.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Establecer propiedades <literal>System</literal>
+ usando <literal>java -Dproperty=value</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Incluir elementos <literal><property></literal>
+ en <literal>hibernate.cfg.xml</literal> (discutido luego).
+ </para>
+ </listitem>
+ </orderedlist>
+
+ <para>
+ <literal>hibernate.properties</literal> es el enfoque más fácil
+ si quieres comenzar rápido.
+ </para>
+
+ <para>
+ La <literal>Configuration</literal> está concebida como un objeto
+ de tiempo de arranque, para ser descartado una vez que una
+ <literal>SessionFactory</literal> es creada.
+ </para>
+
+ </sect1>
+
+ <sect1 id="configuration-sessionfactory">
+ <title>Obteniendo una SessionFactory</title>
+
+ <para>
+ Cuando todos los mapeos han sido parseados por la <literal>Configuration</literal>,
+ la aplicación debe obtener una fábrica de instancias de <literal>Session</literal>.
+ Esta fábrica está concebida para ser compartida por todas las hebras de
+ aplicación:
+ </para>
+
+ <programlisting><![CDATA[SessionFactory sessions = cfg.buildSessionFactory();]]></programlisting>
+
+ <para>
+ Hibernate permite que tu aplicación instancie más de una
+ <literal>SessionFactory</literal>. Esto es útil si estás usando
+ más de una base de datos.
+ </para>
+
+ </sect1>
+
+ <sect1 id="configuration-hibernatejdbc" revision="1">
+ <title>Conexiones JDBC</title>
+
+ <para>
+ Usualmente, quieres que la <literal>SessionFactory</literal> cree y almacene
+ en pool conexiones JDBC para ti. Si adoptas este enfoque, abrir una <literal>Session</literal>
+ es tan simple como:
+ </para>
+
+ <programlisting><![CDATA[Session session = sessions.openSession(); // open a new Session]]></programlisting>
+
+ <para>
+ En cuanto hagas algo que requiera acceso a la base de datos, se obtendrá una
+ conexión JDBC del pool.
+ </para>
+
+ <para>
+ Para que esto funcione, necesitamos pasar algunas propiedades de conexión
+ JDBC a Hibernate. Todos los nombres de propiedades y su semántica
+ están definidas en la clase <literal>org.hibernate.cfg.Environment</literal>.
+ Describiremos ahora las configuraciones más importantes para la conexión
+ JDBC.
+ </para>
+
+ <para>
+ Hibernate obtendrá (y tendrá en pool) conexiones usando
+ <literal>java.sql.DriverManager</literal> si configuras las siguientes propiedades:
+ </para>
+
+ <table frame="topbot">
+ <title>Propiedades JDBC de Hibernate</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Nombre de propiedad</entry>
+ <entry>Propósito</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>hibernate.connection.driver_class</literal>
+ </entry>
+ <entry>
+ <emphasis>clase del driver jdbc</emphasis>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.url</literal>
+ </entry>
+ <entry>
+ <emphasis>URL de jdbc</emphasis>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.username</literal>
+ </entry>
+ <entry>
+ <emphasis>usuario de base de datos</emphasis>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.password</literal>
+ </entry>
+ <entry>
+ <emphasis>contraseña del usuario de base de datos</emphasis>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.pool_size</literal>
+ </entry>
+ <entry>
+ <emphasis>número máximo de conexiones manejadas por pooling</emphasis>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ El algoritmo de pooling de conexiones propio de Hibernate es sin embargo
+ algo rudimentario. Está concebido para ayudarte a comenzar y
+ <emphasis>no está concebido para usar en un sistema de producción</emphasis>
+ ni siquiera para pruebas de rendimiento. Debes usar un pool de terceros para
+ un mejor rendimiento y estabilidad. Sólo remplaza la propiedad
+ <literal>hibernate.connection.pool_size</literal> con configuraciones
+ específicas del pool de conexiones. Esto desactivará el pool
+ interno de Hibernate. Por ejemplo, podrías querer usar C3P0.
+ </para>
+
+ <para>
+ C3P0 es un pool de conexiones JDBC de código abierto distribuido
+ junto a Hibernate en el directorio <literal>lib</literal>.
+ Hibernate usará su <literal>C3P0ConnectionProvider</literal>
+ para pooling de conexiones si estableces propiedades <literal>hibernate.c3p0.*</literal>.
+ Si quieres usar Proxool refiérete al <literal>hibernate.properties</literal>
+ empaquetado y al sitio web de Hibernate para más información.
+ </para>
+
+ <para>
+ Aquí hay un fichero <literal>hibernate.properties</literal> de ejemplo para C3P0:
+ </para>
+
+ <programlisting id="c3p0-configuration" revision="1"><![CDATA[hibernate.connection.driver_class = org.postgresql.Driver
+hibernate.connection.url = jdbc:postgresql://localhost/mydatabase
+hibernate.connection.username = myuser
+hibernate.connection.password = secret
+hibernate.c3p0.min_size=5
+hibernate.c3p0.max_size=20
+hibernate.c3p0.timeout=1800
+hibernate.c3p0.max_statements=50
+hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
+
+ <para>
+ Para su uso en un servidor de aplicaciones, casi siempre debes configurar
+ Hibernate para que obtenga conexiones de un <literal>Datasource</literal>
+ del servidor de aplicaciones registrado en JNDI. Necesitarás establecer
+ al menos una de las siguientes propiedades:
+ </para>
+
+ <table frame="topbot">
+ <title>Propiedades de Datasource de Hibernate</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Nombre de propiedad</entry>
+ <entry>Propósito</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>hibernate.connection.datasource</literal>
+ </entry>
+ <entry>
+ <emphasis>nombre del datasource JNDI</emphasis>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jndi.url</literal>
+ </entry>
+ <entry>
+ <emphasis>URL del provedor JNDI</emphasis> (optional)
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jndi.class</literal>
+ </entry>
+ <entry>
+ <emphasis>clase de la <literal>InitialContextFactory</literal> de JNDI</emphasis> (opcional)
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.username</literal>
+ </entry>
+ <entry>
+ <emphasis>usuario de base de datos</emphasis> (opcional)
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.password</literal>
+ </entry>
+ <entry>
+ <emphasis>contraseña del usuario de base de datos</emphasis> (opcional)
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ He aquí un fichero <literal>hibernate.properties</literal> de ejemplo
+ para un un datasource JNDI provisto por un servidor de aplicaciones.
+ </para>
+
+ <programlisting><![CDATA[hibernate.connection.datasource = java:/comp/env/jdbc/test
+hibernate.transaction.factory_class = \
+ org.hibernate.transaction.JTATransactionFactory
+hibernate.transaction.manager_lookup_class = \
+ org.hibernate.transaction.JBossTransactionManagerLookup
+hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect]]></programlisting>
+
+ <para>
+ Las conexiones JDBC obtenidas de un datasource JNDI participarán automáticamente
+ en las transacciones del servidor de aplicaciones manejadas por contenedor.
+ </para>
+
+ <para>
+ Pueden darse propiedades de conexión arbitrarias anteponiendo
+ "<literal>hibernate.connnection</literal>" al nombre de propiedad.
+ Por ejemplo, puedes especificar un <literal>charSet</literal> usando
+ <literal>hibernate.connection.charSet</literal>.
+ </para>
+
+ <para>
+ Puedes definir tu propia estrategia de plugin para obtener conexiones JDBC implementando
+ la interface <literal>org.hibernate.connection.ConnectionProvider</literal>. Puedes
+ seleccionar una implementación personalizada estableciendo
+ <literal>hibernate.connection.provider_class</literal>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="configuration-optional" revision="1">
+ <title>Parámetros de configuración opcionales</title>
+
+ <para>
+ Hay un número de otras propiedades que controlan el comportamiento
+ de Hibernate en tiempo de ejecución. Todas son opcionales y tienen
+ valores por defecto razonables.
+ </para>
+
+ <para>
+ <emphasis>Advertencia: algunas de estas propiedades son de "nivel-de-sistema"
+ solamente.</emphasis>. Las propiedades a nivel de sistema sólo pueden ser
+ establecidas por medio de <literal>java -Dproperty=value</literal> o
+ <literal>hibernate.properties</literal>. <emphasis>No</emphasis> pueden
+ establecerse por medio de las otras técnicas arriba descritas.
+ </para>
+
+ <table frame="topbot" id="configuration-optional-properties" revision="8">
+ <title>Propiedades de Configuración de Hibernate</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Nombre de propiedad</entry>
+ <entry>Propósito</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>hibernate.dialect</literal>
+ </entry>
+ <entry>
+ El nombre de clase de un <literal>Dialect</literal>
+ de Hibernate que permite a Hibernate generar SQL optimizado
+ para una base de datos relacional en particular.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>full.classname.of.Dialect</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.show_sql</literal>
+ </entry>
+ <entry>
+ Escribe todas las sentencias SQL a la consola.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.default_schema</literal>
+ </entry>
+ <entry>
+ Cualifica, en el SQL generado, los nombres de tabla sin cualificar
+ con el esquema/tablespace dado.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>SCHEMA_NAME</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.default_catalog</literal>
+ </entry>
+ <entry>
+ Cualifica, en el SQL generado, los nombres de tabla sin cualificar
+ con el catálogo dado.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>CATALOG_NAME</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.session_factory_name</literal>
+ </entry>
+ <entry>
+ La <literal>SessionFactory</literal> será
+ ligada a este nombre en JNDI automáticamente
+ después de ser creada.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>jndi/composite/name</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.max_fetch_depth</literal>
+ </entry>
+ <entry>
+ Establece una "profundidad" máxima del
+ árbol de recuperación por outer join
+ para asociaciones de un extremo solo (uno-a-uno, muchos-a-uno).
+ Un <literal>0</literal> deshabilita la recuperación
+ por outer join por defecto.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ valores recomendados entre <literal>0</literal> y
+ <literal>3</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.default_batch_fetch_size</literal>
+ </entry>
+ <entry>
+ Establece un tamaño por defecto para la recuperación
+ en lote de asociaciones de Hibernate.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ valores recomendados <literal>4</literal>, <literal>8</literal>,
+ <literal>16</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.default_entity_mode</literal>
+ </entry>
+ <entry>
+ Establece un modo por defecto de representación de
+ entidades para todas las sesiones abiertas por esta
+ <literal>SessionFactory</literal>
+ <para>
+ <literal>dynamic-map</literal>, <literal>dom4j</literal>,
+ <literal>pojo</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.order_updates</literal>
+ </entry>
+ <entry>
+ Fuerza a Hibernate a ordenar las actualizaciones SQL
+ por el valor de la clave primaria de los items a actualizar.
+ Esto resultará en menos bloqueos muertos de transacción
+ en sistemas altamente concurrentes.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.generate_statistics</literal>
+ </entry>
+ <entry>
+ De habilitarse, Hibernate colectará estadísticas
+ útiles para la afinación de rendimiento.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.use_identifer_rollback</literal>
+ </entry>
+ <entry>
+ De habilitarse, las propiedades identificadoras
+ generadas serán reseteadas a valores por
+ defecto cuando los objetos sean borrados.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.use_sql_comments</literal>
+ </entry>
+ <entry>
+ De activarse, Hibernate generará comentarios dentro del SQL,
+ para una más fácil depuración, por defecto a
+ <literal>false</literal>.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table frame="topbot" id="configuration-jdbc-properties" revision="8">
+ <title>Propiedades de JDBC y Conexiones de Hibernate</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Nombre de propiedad</entry>
+ <entry>Propoósito</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>hibernate.jdbc.fetch_size</literal>
+ </entry>
+ <entry>
+ Un valor distinto de cero que determina el tamaño
+ de recuperación de JDBC (llama a
+ <literal>Statement.setFetchSize()</literal>).
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jdbc.batch_size</literal>
+ </entry>
+ <entry>
+ Un valor distinto de cero habilita el uso de actualizaciones
+ en lote de JDBC2 por Hibernate.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ valores recomendados entre <literal>5</literal> y <literal>30</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jdbc.batch_versioned_data</literal>
+ </entry>
+ <entry>
+ Establece esta propiedad a <literal>true</literal> si tu driver JDBC
+ devuelve cuentas correctas de filas desde <literal>executeBatch()</literal>
+ (usualmente es seguro activar esta opción). Hibernate usará
+ DML en lote para versionar automáticamente los datos.
+ Por defecto a <literal>false</literal>.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jdbc.factory_class</literal>
+ </entry>
+ <entry>
+ Selecciona un <literal>Batcher</literal> personalizado.
+ La mayoría de las aplicaciones no necesitarán
+ esta propiedad de configuración.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>classname.of.BatcherFactory</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jdbc.use_scrollable_resultset</literal>
+ </entry>
+ <entry>
+ Habilita el uso de resultados scrollables de JDBC2 por Hibernate.
+ Esta propiedad sólo es necesaria cuando se usan conexiones
+ JDBC provistas por el usuario, en caso contrario Hibernate usa los
+ metadatos de conexión.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jdbc.use_streams_for_binary</literal>
+ </entry>
+ <entry>
+ Usa flujos (streams) al escribir/leer tipos
+ <literal>binary</literal> o <literal>serializable</literal>
+ a/desde JDBC (propiedad a nivel de sistema).
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jdbc.use_get_generated_keys</literal>
+ </entry>
+ <entry>
+ Habilita el uso de <literal>PreparedStatement.getGeneratedKeys()</literal>
+ de JDBC3 para traer claves generadas nativamente después de insertar.
+ Requiere un driver JDBC3+ y un JRE1.4+. Establécela a false si tu
+ driver tiene problemas con los generadores de identificador de Hibernate.
+ Por defecto, se intenta determinar las capacidades del driver usando los
+ metadatos de conexión.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>true|false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.provider_class</literal>
+ </entry>
+ <entry>
+ EL nombre de clase de un <literal>ConnectionProvider</literal> personalizado
+ que provea conexiones JDBC a Hibernate.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>classname.of.ConnectionProvider</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.isolation</literal>
+ </entry>
+ <entry>
+ Establece el nivel de aislamiento de transacción JDBC.
+ Comprueba <literal>java.sql.Connection</literal> para valores
+ significativos pero observa que la mayoría de las bases de
+ datos no soportan todos los niveles de aislamiento.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>1, 2, 4, 8</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.autocommit</literal>
+ </entry>
+ <entry>
+ Habilita compromiso automático (autocommit) para
+ las conexiones JDBC en pool (no recomendado).
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.release_mode</literal>
+ </entry>
+ <entry>
+ Especifica cuándo Hibernate debe liberar las conexiones JDBC.
+ Por defecto, una conexión JDBC es retenida hasta que la sesión
+ es cerrada explícitamente o desconectada. Para un datasource JTA
+ del servidor de aplicaciones, debes usar <literal>after_statement</literal>
+ para liberar agresivamente las conexiones después de cada llamada
+ JDBC. Para una conexión no JTA, frecuentemente tiene sentido liberar
+ la conexión al final de cada transacción, usando
+ <literal>after_transaction</literal>. <literal>auto</literal> eligirá
+ <literal>after_statement</literal> para las estrategias JTA o CMT
+ de transacción y <literal>after_transaction</literal> para la
+ estrategia JDBC de transacción.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>on_close</literal> (por defecto)| <literal>after_transaction</literal> |
+ <literal>after_statement</literal> | <literal>auto</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.connection.<emphasis><propertyName></emphasis></literal>
+ </entry>
+ <entry>
+ Pasa la propiedad JDBC <literal>propertyName</literal>
+ a <literal>DriverManager.getConnection()</literal>.
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.jndi.<emphasis><propertyName></emphasis></literal>
+ </entry>
+ <entry>
+ Pasa la propiedad <literal>propertyName</literal>
+ a <literal>InitialContextFactory</literal> de JNDI.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table frame="topbot" id="configuration-cache-properties" revision="7">
+ <title>Propiedades de Caché de Hibernate</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Nombre de propiedad</entry>
+ <entry>Propósito</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>hibernate.cache.provider_class</literal>
+ </entry>
+ <entry>
+ El nombre de clase de un <literal>CacheProvider</literal> personalizado.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>classname.of.CacheProvider</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.cache.use_minimal_puts</literal>
+ </entry>
+ <entry>
+ Optimiza la operación del caché de segundo nivel
+ para minimizar escrituras, al costo de lecturas más frecuentes.
+ Esto es más útil para cachés en cluster y,
+ en Hibernate3, está habilitado por defecto para implementaciones
+ de caché en cluster.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>true|false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.cache.use_query_cache</literal>
+ </entry>
+ <entry>
+ Habilita el caché de lectura, consultas individuales todavía
+ tienen que ponerse cachables.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>true|false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.cache.use_second_level_cache</literal>
+ </entry>
+ <entry>
+ Puede ser usado para deshabilitar completamente el caché
+ de segundo nivel, que está habilitado por defecto para clases
+ que especifican un mapeo <literal><cache></literal>.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>true|false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.cache.query_cache_factory</literal>
+ </entry>
+ <entry>
+ El nombre de clase de una interface <literal>QueryCache</literal>
+ personalizada, por defecto al <literal>StandardQueryCache</literal>
+ prefabricado.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>classname.of.QueryCache</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.cache.region_prefix</literal>
+ </entry>
+ <entry>
+ Un prefijo a usar para los nombres de región
+ del caché de segundo nivel.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>prefix</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.cache.use_structured_entries</literal>
+ </entry>
+ <entry>
+ Fuerza a Hibernate a almacenar los datos en el caché
+ de segundo nivel en un formato más amigable al humano.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>true|false</literal>
+ </para>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table frame="topbot" id="configuration-transaction-properties" revision="8">
+ <title>Propiedades de Transacción de Hibernate</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Nombre de propiedad</entry>
+ <entry>Propósito</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>hibernate.transaction.factory_class</literal>
+ </entry>
+ <entry>
+ El nombre de clase de un <literal>TransactionFactory</literal>
+ a usar con la API de <literal>Transaction</literal> de Hibernate
+ (por defectoa <literal>JDBCTransactionFactory</literal>).
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>classname.of.TransactionFactory</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>jta.UserTransaction</literal>
+ </entry>
+ <entry>
+ Un nombre JNDI usado por <literal>JTATransactionFactory</literal> para
+ obtener la <literal>UserTransaction</literal> JTA del servidor
+ de aplicaciones.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>jndi/composite/name</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.transaction.manager_lookup_class</literal>
+ </entry>
+ <entry>
+ El nombre de clase de un <literal>TransactionManagerLookup</literal>
+ requerido cuando el chaché a nivel de JVM está
+ habilitado o cuando se usa un generador alto/bajo en un
+ entorno JTA.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>classname.of.TransactionManagerLookup</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.transaction.flush_before_completion</literal>
+ </entry>
+ <entry>
+ De habilitarse, la sesión se limpiará (flushed)
+ automáticamente durante la fase previa a la compleción
+ de la transacción. (Muy útil cuando se usa Hibernate
+ con CMT).
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.transaction.auto_close_session</literal>
+ </entry>
+ <entry>
+ De habilitarse, la sesión será cerrada automáticamente
+ durante la fase posterior a la compleción de la transacción.
+ (Muy útil cuando se usa Hibernate con CMT).
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table frame="topbot" id="configuration-misc-properties" revision="7">
+ <title>Propiedades Misceláneas</title>
+ <tgroup cols="2">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Nombre de propiedad</entry>
+ <entry>Propósito</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ <literal>hibernate.query.factory_class</literal>
+ </entry>
+ <entry>
+ Elige la implementación de parser HQL.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>org.hibernate.hql.ast.ASTQueryTranslatorFactory</literal> or
+ <literal>org.hibernate.hql.classic.ClassicQueryTranslatorFactory</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.query.substitutions</literal>
+ </entry>
+ <entry>
+ Mapeos de símbolos en consultas Hibernate a
+ símbolos SQL. (los símbolos puedem ser
+ nombres de función o literales, por ejemplo).
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.hbm2ddl.auto</literal>
+ </entry>
+ <entry>
+ Exporta automáticamente DDL de esquema cuando
+ al crear la <literal>SessionFactory</literal>.
+ Con <literal>create-drop</literal>, el esquema de
+ base de datos será desechado cuando la
+ <literal>SessionFactory</literal> se cierre explícitamente.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>update</literal> | <literal>create</literal> | <literal>create-drop</literal>
+ </para>
+ </entry>
+ </row>
+ <row>
+ <entry>
+ <literal>hibernate.cglib.use_reflection_optimizer</literal>
+ </entry>
+ <entry>
+ Habilita el uso de CGLIB en vez de refleccón en tiempo de
+ ejecución (propiedad a nivel de sistema). La reflección
+ a veces puede ser útil ante la aparición de problemas.
+ Observa que Hibernate siempre requiere CGLIB incluso si desactivas
+ el optimizador. No puedes establecer esta propiedad en
+ <literal>hibernate.cfg.xml</literal>.
+ <para>
+ <emphasis role="strong">ej.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <sect2 id="configuration-optional-dialects" revision="1">
+ <title>SQL Dialects</title>
+
+ <para>
+ You should always set the <literal>hibernate.dialect</literal> property to the correct
+ <literal>org.hibernate.dialect.Dialect</literal> subclass for your database. If you
+ specify a dialect, Hibernate will use sensible defaults for some of the
+ other properties listed above, saving you the effort of specifying them manually.
+ </para>
+
+ <table frame="topbot" id="sql-dialects" revision="2">
+ <title>Dialectos SQL de Hibernate(<literal>hibernate.dialect</literal>)</title>
+ <tgroup cols="2">
+ <colspec colwidth="1*"/>
+ <colspec colwidth="2.5*"/>
+ <thead>
+ <row>
+ <entry>RDBMS</entry>
+ <entry>Dialecto</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>DB2</entry> <entry><literal>org.hibernate.dialect.DB2Dialect</literal></entry>
+ </row>
+ <row>
+ <entry>DB2 AS/400</entry> <entry><literal>org.hibernate.dialect.DB2400Dialect</literal></entry>
+ </row>
+ <row>
+ <entry>DB2 OS390</entry> <entry><literal>org.hibernate.dialect.DB2390Dialect</literal></entry>
+ </row>
+ <row>
+ <entry>PostgreSQL</entry> <entry><literal>org.hibernate.dialect.PostgreSQLDialect</literal></entry>
+ </row>
+ <row>
+ <entry>MySQL</entry> <entry><literal>org.hibernate.dialect.MySQLDialect</literal></entry>
+ </row>
+ <row>
+ <entry>MySQL con InnoDB</entry> <entry><literal>org.hibernate.dialect.MySQLInnoDBDialect</literal></entry>
+ </row>
+ <row>
+ <entry>MySQL con MyISAM</entry> <entry><literal>org.hibernate.dialect.MySQLMyISAMDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Oracle (cualquier versión)</entry> <entry><literal>org.hibernate.dialect.OracleDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Oracle 9i/10g</entry> <entry><literal>org.hibernate.dialect.Oracle9Dialect</literal></entry>
+ </row>
+ <row>
+ <entry>Sybase</entry> <entry><literal>org.hibernate.dialect.SybaseDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Sybase Anywhere</entry> <entry><literal>org.hibernate.dialect.SybaseAnywhereDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Microsoft SQL Server</entry> <entry><literal>org.hibernate.dialect.SQLServerDialect</literal></entry>
+ </row>
+ <row>
+ <entry>SAP DB</entry> <entry><literal>org.hibernate.dialect.SAPDBDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Informix</entry> <entry><literal>org.hibernate.dialect.InformixDialect</literal></entry>
+ </row>
+ <row>
+ <entry>HypersonicSQL</entry> <entry><literal>org.hibernate.dialect.HSQLDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Ingres</entry> <entry><literal>org.hibernate.dialect.IngresDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Progress</entry> <entry><literal>org.hibernate.dialect.ProgressDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Mckoi SQL</entry> <entry><literal>org.hibernate.dialect.MckoiDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Interbase</entry> <entry><literal>org.hibernate.dialect.InterbaseDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Pointbase</entry> <entry><literal>org.hibernate.dialect.PointbaseDialect</literal></entry>
+ </row>
+ <row>
+ <entry>FrontBase</entry> <entry><literal>org.hibernate.dialect.FrontbaseDialect</literal></entry>
+ </row>
+ <row>
+ <entry>Firebird</entry> <entry><literal>org.hibernate.dialect.FirebirdDialect</literal></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </sect2>
+
+ <sect2 id="configuration-optional-outerjoin" revision="4">
+ <title>Recuperación por Unión Externa (Outer Join Fetching)</title>
+
+ <para>
+ Si tu base de datos soporta uniones externas del estilo ANSI, Oracle o Sybase, la
+ <emphasis>recuperación por unión externa</emphasis> aumentará
+ frecuentemente el rendimiento limitando el número de llamadas a la base de datos
+ (al costo de más trabajo posiblemente realizado por la base de datos misma).
+ La recuperación por unión externa permite que un grafo completo de objetos
+ conectados por asociaciones muchos-a-uno, uno-a-muchos, muchos-a-muchos y uno-a-uno sea
+ traído en una sola <literal>SELECT</literal> SQL.
+ </para>
+
+ <para>
+ La recuperación por unión externa puede ser deshabilitada
+ <emphasis>globalmente</emphasis> estableciendo la propiedad
+ <literal>hibernate.max_fetch_depth</literal> a <literal>0</literal>.
+ Un valor de <literal>1</literal> o mayor habilita la recuperación
+ por unión externa para asociaciones uno-a-uno y muchos-a-uno que
+ hayan sido mapeadas con <literal>fetch="join"</literal>.
+ </para>
+
+ <para>
+ Ver <xref linkend="performance-fetching"/> para más información.
+ </para>
+
+ </sect2>
+
+ <sect2 id="configuration-optional-binarystreams" revision="1">
+ <title>Flujos Binarios</title>
+
+ <para>
+ Oracle limita el tamaño de arrays de <literal>byte</literal>
+ que puedan ser pasados a/desde su driver JDBC. Si deseas usar instancias
+ grandes de tipo <literal>binary</literal> o <literal>serializable</literal>,
+ debes habilitar <literal>hibernate.jdbc.use_streams_for_binary</literal>.
+ <emphasis>Esta es una propiedad a nivel de sistema solamente.</emphasis>
+ </para>
+
+ </sect2>
+
+ <sect2 id="configuration-optional-cacheprovider" revision="2">
+ <title>Caché de segundo nivel y de lectura</title>
+
+ <para>
+ Las propiedades prefijadas por <literal>hibernate.cache</literal>
+ te permiten usar un sistema de caché de segundo nivel
+ en el ámbito de un proceso o cluster con Hibernate.
+ Ver <xref linkend="performance-cache"/> para más detalles.
+ </para>
+
+ </sect2>
+
+ <sect2 id="configuration-optional-querysubstitution">
+ <title>Sustitución de Lenguaje de Consulta</title>
+
+ <para>
+ Puedes definir nuevos símbolos de consulta de Hibernate usando
+ <literal>hibernate.query.substitutions</literal>. Por ejemplo:
+ </para>
+
+ <programlisting>hibernate.query.substitutions true=1, false=0</programlisting>
+
+ <para>
+ causaría que los símbolos <literal>true</literal> y <literal>false</literal> sean
+ traducidos a literales enteros en el SQL generado.
+ </para>
+
+ <programlisting>hibernate.query.substitutions toLowercase=LOWER</programlisting>
+
+ <para>
+ te permitiría renombrar la función <literal>LOWER</literal> de SQL.
+ </para>
+
+ </sect2>
+
+ <sect2 id="configuration-optional-statistics" revision="2">
+ <title>Hibernate statistics</title>
+
+ <para>
+ Si habilitas <literal>hibernate.generate_statistics</literal>, Hibernate
+ expondrá un número de métricas que son útiles
+ al afinar un sistema en ejecución vía
+ <literal>SessionFactory.getStatistics()</literal>. Hibernate puede incluso ser
+ configurado para exponer estas estadísticas vía JMX. Lee el
+ Javadoc de las interfaces en <literal>org.hibernate.stats</literal>
+ para más información.
+ </para>
+
+ </sect2>
+ </sect1>
+
+ <sect1 id="configuration-logging">
+ <title>Registros de mensajes (Logging)</title>
+
+ <para>
+ Hibernate registra varios eventos usando commons-logging
+ de Apache.
+ </para>
+
+ <para>
+ El servicio de commons-logging saldrá directamente ya sea a
+ Log4J (si incluyes <literal>log4j.jar</literal> in your classpath) o
+ JDK1.4 logging (al ejecutar bajo JDK1.4 o superior). Puedes descargar
+ Log4J desde <literal>http://logging.apache.org</literal>. Para usar
+ Log4J necesitarás colocar un fichero <literal>log4j.properties</literal>
+ en tu classpath. Un fichero de propiedades de ejemplo se distribuye con
+ Hibernate en el directorio <literal>src/</literal>.
+ </para>
+
+ <para>
+ Recomendamos fuertemente que te familiarices con los registros de mensajes
+ de Hibernate. Se ha puesto un gran trabajo en hacer los registros de Hibernate
+ tan detallados como se puede, sin hacerlos ilegibles. Es un dispositivo esencial
+ en la resolución de problemas. Las categorías de registro
+ más interesantes son las siguientes:
+ </para>
+
+ <table frame="topbot" id="log-categories" revision="2">
+ <title>Categorías de Registro de Hibernate</title>
+ <tgroup cols="2">
+ <colspec colwidth="1*"/>
+ <colspec colwidth="2.5*"/>
+ <thead>
+ <row>
+ <entry>Categoría</entry>
+ <entry>Función</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>org.hibernate.SQL</literal></entry>
+ <entry>Registra todas las sentencias DML de SQL a
+ medida que se ejecutan</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.type</literal></entry>
+ <entry>Registra todos los parámetros JDBC</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.tool.hbm2ddl</literal></entry>
+ <entry>Registra todas las sentencias DDL de SQL a
+ medida que se ejecutan</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.pretty</literal></entry>
+ <entry>
+ Registra el estado de todas las entidades (máximo
+ de 20 entidades) asociadas con la sesión en tiempo
+ de limpieza (flush)
+ </entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.cache</literal></entry>
+ <entry>Registra toda la actividad del caché de segundo nivel</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction</literal></entry>
+ <entry>Registra la actividad relacionada con la transacción</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.jdbc</literal></entry>
+ <entry>Registra toda adquisición de recursos JDBC</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.hql.ast</literal></entry>
+ <entry>Regista los ASTs de HQL y SQL, así como
+ otra información sobre análisis de consultas.</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.secure</literal></entry>
+ <entry>Registra todas las peticiones de autorización JAAS</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate</literal></entry>
+ <entry>
+ Registra todo (mucha información, pero muy útil
+ para la resolución de problemas)
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ Al desarrollar aplicacinoes con Hibernate, casi siempre debes trabajar con
+ <literal>debug</literal> habilitado para la categoría <literal>org.hibernate.SQL</literal>
+ o, alternativamente, la propiedad <literal>hibernate.show_sql</literal> habilitada.
+ </para>
+
+
+ </sect1>
+
+ <sect1 id="configuration-namingstrategy">
+ <title>Implementando una <literal>NamingStrategy</literal></title>
+
+ <para>
+ La interface <literal>org.hibernate.cfg.NamingStrategy</literal> te permite
+ especificar un "estándar de nombrado" para objetos de la base de datos
+ y elementos de esquema.
+ </para>
+
+ <para>
+ Puedes proveer reglas para generar automáticamente identificadores de
+ base de datos a partir de identificadores JDBC o para procesar nombres
+ "lógicos" de columnas y tablas dados en el fichero de mapeo en nombres
+ "físicos" de columnas y tablas. Esta funcionalidad ayuda a reducir
+ la verborragia del documento de mapeo, eliminando ruido repetitivo
+ (prefijos <literal>TBL_</literal>, por ejemplo). La estrategia por defecto
+ usada por Hibernate mínima en absoluto.
+ </para>
+
+ <para>
+ Puedes especificar una estrategia diferente llamando a
+ <literal>Configuration.setNamingStrategy()</literal> antes de agregar los mapeos:
+ </para>
+
+ <programlisting><![CDATA[SessionFactory sf = new Configuration()
+ .setNamingStrategy(ImprovedNamingStrategy.INSTANCE)
+ .addFile("Item.hbm.xml")
+ .addFile("Bid.hbm.xml")
+ .buildSessionFactory();]]></programlisting>
+
+ <para>
+ <literal>org.hibernate.cfg.ImprovedNamingStrategy</literal>
+ es una estrategia prefabricada que puede ser un punto de
+ partida útil para algunas aplicaciones.
+ </para>
+
+ </sect1>
+
+ <sect1 id="configuration-xmlconfig" revision="2">
+ <title>Fichero de configuración XML</title>
+
+ <para>
+ Un enfoque alternativo de configuración es especificar una
+ configuración completa en un fichero llamado <literal>hibernate.cfg.xml</literal>.
+ Este fichero puede ser usado como un remplazo del fichero <literal>hibernate.properties</literal> o,
+ si ambos están presentes, para sobrescribir propiedades.
+ </para>
+
+ <para>
+ El fichero de configuración XML se espera por defecto en la
+ raíz o tu <literal>CLASSPATH</literal>. He aquí un ejemplo:
+ </para>
+
+ <programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+ "-//Hibernate/Hibernate Configuration DTD//EN"
+ "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+ <!-- a SessionFactory instance listed as /jndi/name -->
+ <session-factory
+ name="java:hibernate/SessionFactory">
+
+ <!-- properties -->
+ <property name="connection.datasource">java:/comp/env/jdbc/MyDB</property>
+ <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
+ <property name="show_sql">false</property>
+ <property name="transaction.factory_class">
+ org.hibernate.transaction.JTATransactionFactory
+ </property>
+ <property name="jta.UserTransaction">java:comp/UserTransaction</property>
+
+ <!-- mapping files -->
+ <mapping resource="org/hibernate/auction/Item.hbm.xml"/>
+ <mapping resource="org/hibernate/auction/Bid.hbm.xml"/>
+
+ <!-- cache settings -->
+ <class-cache class="org.hibernate.auction.Item" usage="read-write"/>
+ <class-cache class="org.hibernate.auction.Bid" usage="read-only"/>
+ <collection-cache collection="org.hibernate.auction.Item.bids" usage="read-write"/>
+
+ </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+
+ <para>
+ Como puedes ver, la ventaja de este enfoque es la externalización de los
+ nombres de los fichero de mapeo a configuración. El
+ <literal>hibernate.cfg.xml</literal> es también más conveniente
+ una vez que hayas afinado el caché de Hibernate. Observa que elección
+ tuya usar ya sea <literal>hibernate.properties</literal> o
+ <literal>hibernate.cfg.xml</literal>, ambos son equivalentes, excepto por los
+ beneficios de usar la sintaxis XML arriba mencionados.
+ </para>
+
+ <para>
+ Con la configuración XML, arrancar Hibernate es tan simple como
+ </para>
+
+ <programlisting><![CDATA[SessionFactory sf = new Configuration().configure().buildSessionFactory();]]></programlisting>
+
+ <para>
+ Puedes tomar un fichero XML diferente usando
+ </para>
+
+ <programlisting><![CDATA[SessionFactory sf = new Configuration()
+ .configure("catdb.cfg.xml")
+ .buildSessionFactory();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="configuration-j2ee" revision="1">
+ <title>Integració con Servidores de Aplicaciones J2EE</title>
+
+ <para>
+ Hibernate tiene los siguientes puntos de integración con la
+ infraestructura J2EE:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Datasources manejados por contenedor</emphasis>: Hibernate puede usar
+ conexiones JDBC manejadas por el contenedor y provistas a través de JNDI.
+ Usualmente, un <literal>TransactionManager</literal> compatible con JTA y un
+ <literal>ResourceManager</literal> cuidan del manejo de transacciones (CMT),
+ esp. manejo de transacciones distribuídas a través de varios
+ datasources. Puedes también, por supuesto, demarcar los límites
+ de las transacciones programáticamente (BMT) o podrías querer usar
+ para esto la API opcional de <literal>Transaction</literal> de Hibernate para
+ mantener tu código portable.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Ligamento Automático JNDI</emphasis>: Hibernate puede ligar sus
+ <literal>SessionFactory</literal> a JNDI después del arranque.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Ligamento de Sesión JTA:</emphasis>
+ La <literal>Session</literal> de Hibernate puede ser ligada automáticamente
+ al ámbito de transacciones JTA si usas EJBs. Simplemente busca la
+ <literal>SessionFactory</literal> de JNDI y obtén la <literal>Session</literal>
+ actual. Deja que Hibernate cuide de limpiar y cerrar la <literal>Session</literal>
+ cuando se complete tu transacción JTA. La demarcación de transacción
+ es declarativa, en descriptores de despliegue de EJB.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Despliegue JMX:</emphasis> Si tienes un servidor de aplicaciones capaz
+ de JMX (por ejemplo, JBoss AS), puedes optar por desplegar Hibernate como un MBean
+ manejado. Esto te ahorra el código de una línea de arranque para
+ construir tu <literal>SessionFactory</literal> desde una <literal>Configuration</literal>.
+ El contenedor arrancará tu <literal>HibernateService</literal>, e idealmente también
+ cuidará de las dependencias entre servicios (El datasource debe estar
+ disponible antes que arranque Hibernate, etc).
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Dependiendo de tu entorno, podrías tener que establecer la opción
+ de configuración <literal>hibernate.connection.aggressive_release</literal>
+ a true si tu servidor de aplicaciones muestra excepciones "connection containment".
+ </para>
+
+ <sect2 id="configuration-optional-transactionstrategy" revision="3">
+ <title>Configuración de la estrategia de transacción</title>
+
+ <para>
+ La API de <literal>Session</literal> de Hibernate es independiente de cualquier
+ demarcación de transacción en tu arquitectura. Si dejas que Hibernate
+ use JDBC directamente, a través de un pool de conexiones. puedes comenzar y
+ acabar tus transacciones llamando la API de JDBC. Si ejecutas en un servidor de
+ aplicaciones J2EE, podréas querer usar transacciones manejadas por bean y
+ llamar la API de JTA y <literal>UserTransaction</literal> cuando sea necesario.
+ </para>
+
+ <para>
+ Para mantener tu código portable entre estos dos (y otros) entornos recomendamos la API
+ de <literal>Transaction</literal> de Hibernate, que envuelve y oculta el sistema subyacente.
+ Tienes que especificar una clase fábrica para las instancias de <literal>Transaction</literal>
+ estableciendo la propiedad de configuración <literal>hibernate.transaction.factory_class</literal>
+ de Hibernate.
+ </para>
+
+ <para>
+ Hay tres elecciones estándar (prefabricadas):
+ </para>
+
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term><literal>org.hibernate.transaction.JDBCTransactionFactory</literal></term>
+ <listitem>
+ <para>delega a transacciones de base de datos (JDBC) (por defecto)</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>org.hibernate.transaction.JTATransactionFactory</literal></term>
+ <listitem>
+ <para>
+ delega a transacciones manejadas por contenedor si una transacción
+ existente estó por debajo en este contexto (ej. método de un
+ bean de sesión EJB), en otro caso una nueva transacción es
+ comenzada y se usan transacciones manejadas por bean.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><literal>org.hibernate.transaction.CMTTransactionFactory</literal></term>
+ <listitem>
+ <para>delega a transacciones JTA manejadas por contenedor</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>
+ Puedes definir también tus propias estrategias de transacción
+ (para un servicio de transacción CORBA, por ejemplo).
+ </para>
+
+ <para>
+ Algunas funcionalidades en Hibernate (ej, el caché de segundo nivel, ligamento
+ automático de JTA y Session, etc.) requieren acceso al <literal>TransactionManager</literal>
+ de JTA en un entorno manejado. En un servidor de aplicaciones tienes que especificar
+ cómo Hibernate debe obtener una referencia al <literal>TransactionManager</literal>,
+ pues J2EE no estandariza un solo mecanismo:
+ </para>
+
+ <table frame="topbot" id="jtamanagerlookup" revision="1">
+ <title>TransactionManagers de JTA</title>
+ <tgroup cols="2">
+ <colspec colwidth="2.5*"/>
+ <colspec colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Transaction Factory</entry>
+ <entry align="center">Servidor de Aplicaciones</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>org.hibernate.transaction.JBossTransactionManagerLookup</literal></entry>
+ <entry align="center">JBoss</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.WeblogicTransactionManagerLookup</literal></entry>
+ <entry align="center">Weblogic</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.WebSphereTransactionManagerLookup</literal></entry>
+ <entry align="center">WebSphere</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.WebSphereExtendedJTATransactionLookup</literal></entry>
+ <entry align="center">WebSphere 6</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.OrionTransactionManagerLookup</literal></entry>
+ <entry align="center">Orion</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.ResinTransactionManagerLookup</literal></entry>
+ <entry align="center">Resin</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.JOTMTransactionManagerLookup</literal></entry>
+ <entry align="center">JOTM</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.JOnASTransactionManagerLookup</literal></entry>
+ <entry align="center">JOnAS</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.JRun4TransactionManagerLookup</literal></entry>
+ <entry align="center">JRun4</entry>
+ </row>
+ <row>
+ <entry><literal>org.hibernate.transaction.BESTransactionManagerLookup</literal></entry>
+ <entry align="center">Borland ES</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </sect2>
+
+ <sect2 id="configuration-optional-jndi" revision="2">
+ <title><literal>SessionFactory</literal> ligada a JNDI</title>
+
+ <para>
+ Una <literal>SessionFactory</literal> de Hibernate ligada a JNDI puede simplificar
+ la obtención de la fábrica y la creación de nuevas
+ <literal>Session</literal>s. Observa que esto no está relacionado a un
+ <literal>Datasource</literal> ligado a JNDI, simplemente ambos usan el mismo
+ registro!
+ </para>
+
+ <para>
+ Si deseas tener la <literal>SessionFactory</literal> ligada a un espacio de nombres de JNDI,
+ especifica un nombre (ej. <literal>java:hibernate/SessionFactory</literal>) usando la
+ propiedad <literal>hibernate.session_factory_name</literal>. Si esta propiedad es omitida,
+ la <literal>SessionFactory</literal> no será ligada a JNDI (Esto es especialmente
+ útil en entornos con una implementació JNDI de sólo lectura por defecto,
+ ej. Tomcat.)
+ </para>
+
+ <para>
+ Al ligar la <literal>SessionFactory</literal> a JNDI, Hibernate usará los valores de
+ <literal>hibernate.jndi.url</literal>, <literal>hibernate.jndi.class</literal> para instanciar
+ un contexto inicial. Si étos no se especifican, se usará el
+ <literal>InitialContext</literal> por defecto.
+ </para>
+
+ <para>
+ Hibernate colocará automáticamente la <literal>SessionFactory</literal>
+ en JNDI después que llames a <literal>cfg.buildSessionFactory()</literal>.
+ Esto significa que tendrás al menos esta llamada en algún código
+ de arranque (o clase de utilidad) en tu aplicación, a menos qie uses el despliegue
+ JMX con el <literal>HibernateService</literal> (discutido luego).
+ </para>
+
+ <para>
+ Si usas una <literal>SessionFactory</literal> de JNDI, un EJB o cualquier otra
+ clase puede obtener la <literal>SessionFactory</literal> usando una búsqueda
+ JNDI. Observa que esta configuración no es necesaria si usas la clase de ayuda
+ <literal>HibernateUtil</literal> introducida en el capítulo uno, que actúa
+ como un registro Singleton. Sin embargo, <literal>HibernateUtil</literal> es más
+ común en un entorno no manejado.
+ </para>
+
+ </sect2>
+
+ <sect2 id="configuration-j2ee-currentsession" revision="1">
+ <title>Ligado automático de JTA y Session</title>
+
+ <para>
+ Para entornos no manejados hemos sugerido <literal>HibernateUtil</literal> con una
+ <literal>SessionFactory</literal> estática, y administración de la
+ <literal>Session</literal> de Hibernate. Este enfoque no es fácil de usar
+ en un entorno EJB, al poder ejecutarse muchos EJBs dentro de la misma transacción
+ pero no en la misma hebra. Recomendados que ligues la <literal>SessionFactory</literal>
+ a JNDI en un entorno manejado.
+ </para>
+
+ <para>
+ En vez de rodar tu propia utilidad de <literal>ThreadLocal</literal>,
+ usa el método <literal>getCurrentSession()</literal> en la
+ <literal>SessionFactory</literal> para obtener una <literal>Session</literal>
+ de Hibernate. Si no hubiese una <literal>Session</literal> de Hibernate en la
+ transacción JTA actual, se arrancará y asignará una.
+ Ambas opciones de configuración <literal>hibernate.transaction.flush_before_completion</literal>
+ y <literal>hibernate.transaction.auto_close_session</literal>, serán establecidas
+ automáticamente para cada <literal>Session</literal> que obtengas con
+ <literal>getCurrentSession()</literal>, de modo que éstas serán
+ limpiadas (flushed) y cerradas automáticamente cuando el contenedor complete
+ las transacciones JTA.
+ </para>
+
+ <para>
+ Si tu, por ejemplo, usas el patrón de diseño DAO para escribir tu
+ capa de persistencia, todos los DAO's buscan la <literal>SessionFactory</literal>
+ cuando se necesite y abren la sesión "actual". No hay necesidad de pasar
+ las instancias de <literal>SessionFactory</literal> o <literal>Session</literal>
+ alrededor entre el código de control y el código DAO.
+ </para>
+
+ </sect2>
+
+ <sect2 id="configuration-j2ee-jmx" revision="1">
+ <title>Despliegue JMX</title>
+
+ <para>
+ La línea <literal>cfg.buildSessionFactory()</literal> todavía tiene
+ que ser ejecutada en algun sitio para obtener una <literal>SessionFactory</literal>
+ en JNDI. Puedes hacer esto bien en un bloque inicializador <literal>static</literal>
+ (como aquel en <literal>HibernateUtil</literal>) o bien despliegas Hibernate como un
+ <emphasis>servicio manejado</emphasis>.
+ </para>
+
+ <para>
+ Hibernate se distribuye con <literal>org.hibernate.jmx.HibernateService</literal>
+ para despliegue en un servidor de aplicaciones con capacidades JMX, como JBoss AS.
+ El despliegue y la configuracón reales son específicos del vendedor.
+ He aquí un <literal>jboss-service.xml</literal> de ejemplo para JBoss 4.0.x:
+ </para>
+
+ <programlisting><![CDATA[<?xml version="1.0"?>
+<server>
+
+<mbean code="org.hibernate.jmx.HibernateService"
+ name="jboss.jca:service=HibernateFactory,name=HibernateFactory">
+
+ <!-- Required services -->
+ <depends>jboss.jca:service=RARDeployer</depends>
+ <depends>jboss.jca:service=LocalTxCM,name=HsqlDS</depends>
+
+ <!-- Bind the Hibernate service to JNDI -->
+ <attribute name="JndiName">java:/hibernate/SessionFactory</attribute>
+
+ <!-- Datasource settings -->
+ <attribute name="Datasource">java:HsqlDS</attribute>
+ <attribute name="Dialect">org.hibernate.dialect.HSQLDialect</attribute>
+
+ <!-- Transaction integration -->
+ <attribute name="TransactionStrategy">
+ org.hibernate.transaction.JTATransactionFactory</attribute>
+ <attribute name="TransactionManagerLookupStrategy">
+ org.hibernate.transaction.JBossTransactionManagerLookup</attribute>
+ <attribute name="FlushBeforeCompletionEnabled">true</attribute>
+ <attribute name="AutoCloseSessionEnabled">true</attribute>
+
+ <!-- Fetching options -->
+ <attribute name="MaximumFetchDepth">5</attribute>
+
+ <!-- Second-level caching -->
+ <attribute name="SecondLevelCacheEnabled">true</attribute>
+ <attribute name="CacheProviderClass">org.hibernate.cache.EhCacheProvider</attribute>
+ <attribute name="QueryCacheEnabled">true</attribute>
+
+ <!-- Logging -->
+ <attribute name="ShowSqlEnabled">true</attribute>
+
+ <!-- Mapping files -->
+ <attribute name="MapResources">auction/Item.hbm.xml,auction/Category.hbm.xml</attribute>
+
+</mbean>
+
+</server>]]></programlisting>
+
+ <para>
+ Este fichero es desplegado en un directorio llamado <literal>META-INF</literal> y
+ empaquetado en un fichero JAR con la extensión <literal>.sar</literal>
+ (fichero de servicio). También necesitas empaquetar Hibernate, sus bibliotecas
+ de terceros requeridas, tus clases persistentes compiladas, así como tus ficheros de mapeo
+ en el mismo fichero. Tus beans de empresa (usualmente beans de sesión) pueden ser
+ mantenidos en su propio fichero JAR, pero debes incluir este fichero EJB JAR en el fichero
+ de servicio principal para obtener una unidad desplegable (en caliente). Consulta la documentación
+ de JBoss AS para más información sobre el servicio JMX y despliegue de EJB.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+</chapter>
+
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/content/events.xml (from rev 12794, core/trunk/documentation/manual/es-ES/src/main/docbook/modules/events.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/events.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/events.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,233 @@
+<chapter id="events">
+ <title>Interceptores y eventos</title>
+
+ <para>
+ Frecuentemente es útil para la aplicación reaccionar a ciertos eventos que ocurran dentro de Hibernate.
+ Esto permite la implementación de ciertos tipos de funcionalidade genérica, y extensión de la
+ funcionalidad de Hibernate.
+ </para>
+
+ <sect1 id="objectstate-interceptors" revision="1">
+ <title>Interceptores</title>
+
+ <para>
+ La interface <literal>Interceptor</literal> provee callbacks desde la sesión a la aplicación
+ permitiendo a ésta última inspeccionar y/o manipular las propiedades de un objeto persistente
+ antes que sea salvado, actualizado, borrado o cargado. Un uso posible de esto es seguir la pista
+ de información de auditoría. Por ejemplo, el siguiente <literal>Interceptor</literal> establece
+ automáticamente el <literal>createTimestamp</literal> cuando un <literal>Auditable</literal> es
+ creado y actualiza la propiedad <literal>lastUpdateTimestamp</literal> cuando un
+ <literal>Auditable</literal> es acutalizado.
+ </para>
+
+ <programlisting><![CDATA[package org.hibernate.test;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.Iterator;
+
+import org.hibernate.Interceptor;
+import org.hibernate.type.Type;
+
+public class AuditInterceptor implements Interceptor, Serializable {
+
+ private int updates;
+ private int creates;
+
+ public void onDelete(Object entity,
+ Serializable id,
+ Object[] state,
+ String[] propertyNames,
+ Type[] types) {
+ // do nothing
+ }
+
+ public boolean onFlushDirty(Object entity,
+ Serializable id,
+ Object[] currentState,
+ Object[] previousState,
+ String[] propertyNames,
+ Type[] types) {
+
+ if ( entity instanceof Auditable ) {
+ updates++;
+ for ( int i=0; i < propertyNames.length; i++ ) {
+ if ( "lastUpdateTimestamp".equals( propertyNames[i] ) ) {
+ currentState[i] = new Date();
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public boolean onLoad(Object entity,
+ Serializable id,
+ Object[] state,
+ String[] propertyNames,
+ Type[] types) {
+ return false;
+ }
+
+ public boolean onSave(Object entity,
+ Serializable id,
+ Object[] state,
+ String[] propertyNames,
+ Type[] types) {
+
+ if ( entity instanceof Auditable ) {
+ creates++;
+ for ( int i=0; i<propertyNames.length; i++ ) {
+ if ( "createTimestamp".equals( propertyNames[i] ) ) {
+ state[i] = new Date();
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ public void postFlush(Iterator entities) {
+ System.out.println("Creations: " + creates + ", Updates: " + updates);
+ }
+
+ public void preFlush(Iterator entities) {
+ updates=0;
+ creates=0;
+ }
+
+ ...
+
+}]]></programlisting>
+
+ <para>
+ El interceptor podría ser especificado cuando se crea la sesión:
+ </para>
+
+ <programlisting><![CDATA[Session session = sf.openSession( new AuditInterceptor() );]]></programlisting>
+
+ <para>
+ Puedes además establecer un interceptor a un nivel global, usando la <literal>Configuration</literal>:
+ </para>
+
+ <programlisting><![CDATA[new Configuration().setInterceptor( new AuditInterceptor() );]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="objectstate-events" revision="2">
+ <title>Sistema de eventos</title>
+
+ <para>
+ Si tienes que reaccionar a eventos particulares en tu capa de persistencia, puedes también la
+ arquitectura de <emphasis>eventos</emphasis> de Hibernate3. El sistema de eventos puede ser usado
+ en adición o como un remplazo a los interceptores.
+ </para>
+
+ <para>
+ Esencialmente todos los métodos de la interface <literal>Session</literal> se correlacionan
+ con un evento. Tienes un <literal>LoadEvent</literal>, un <literal>FlushEvent</literal>, etc
+ (consulta el DTD del fichero de configuración XML o el paquete <literal>org.hibernate.event</literal>
+ para la lista completa de tipos de evento definidos). Cuando se hace una petición de uno de estos
+ métodos, la <literal>Session</literal> de Hibernate genera un evento apropiado y se lo pasa
+ al oyente (listener) de eventos configurado para ese tipo. De fábrica, estos oyentes implementan
+ el mismo procesamiento en los que siempre resultan aquellos métodos. Sin embargo, eres libre de
+ implementar una personalización de una de las interfaces oyentes (es decir, el
+ <literal>LoadEvent</literal> es procesado por la implementación registrada de la interface
+ <literal>LoadEventListener</literal>), en cuyo caso su implementación sería responsable
+ de procesar cualquier petición <literal>load()</literal> hecha a la <literal>Session</literal>.
+ </para>
+
+ <para>
+ Los oyentes deben ser considerados efectivamente singletons; quiere decir, que son compartidos
+ entre las peticiones, y por lo tanto no guardan ningún estado en variables de instancia.
+ </para>
+
+ <para>
+ Un oyente personalizado debe implementar la interface apropiada para el evento que quiere procesar y/o
+ extender una de las clases base de conveniencia (o incluso los oyentes de eventos por defecto
+ usados por Hibernate de fábrica al ser éstos declarados non-final para este propósito). Los
+ oyentes personalizados pueden ser registrados programáticamente a través del objeto
+ <literal>Configuration</literal>, o especificados en el XML de configuración de Hibernate
+ (la declaración declarativa a través del fichero de propiedades no está soportada).
+ He aquí un ejemplo de un oyente personalizado de eventos load:
+ </para>
+
+ <programlisting><![CDATA[public class MyLoadListener extends DefaultLoadEventListener {
+ // this is the single method defined by the LoadEventListener interface
+ public Object onLoad(LoadEvent event, LoadEventListener.LoadType loadType)
+ throws HibernateException {
+ if ( !MySecurity.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) {
+ throw MySecurityException("Unauthorized access");
+ }
+ return super.onLoad(event, loadType);
+ }
+}]]></programlisting>
+
+ <para>
+ Necesitas además una entrada de configuración diciéndole a Hibernate que use el
+ oyente en vez del oyente por defecto:
+ </para>
+
+<programlisting><![CDATA[<hibernate-configuration>
+ <session-factory>
+ ...
+ <listener type="load" class="MyLoadListener"/>
+ </session-factory>
+</hibernate-configuration>]]></programlisting>
+
+ <para>
+ En cambio, puedes registrarlo programáticamente:
+ </para>
+
+ <programlisting><![CDATA[Configuration cfg = new Configuration();
+cfg.getSessionEventListenerConfig().setLoadEventListener( new MyLoadListener() );]]></programlisting>
+
+ <para>
+ Los oyentes registrados declarativamente no pueden compartir instancias. Si el mismo nombre de clase es
+ usado en múltiples elementos <literal><listener/></literal>, cada referencia resultará en una instancia
+ separada de esa clase. Si necesitas la capacidad de compartir instancias de oyentes entre tipos de oyente
+ debes usar el enfoque de registración programática.
+ </para>
+
+ <para>
+ ¿Por qué implementar una interface y definir el tipo espcífico durante la configuración?
+ Bueno, una implementación de oyente podría implementar múltiples interfaces de oyente
+ de eventos. Teniendo el tipo definido adicionalmente durante la registración lo hace más
+ fácil para activar o desactivar oyentes personalizados durante la configuración.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-decl-security">
+ <title>Seguridad declarativa de Hibernate</title>
+ <para>
+ Usualmente, la seguridad declarativa en aplicaciones Hibernate es manejada en una capa de fachada
+ de sesión. Ahora, Hibernate3 permite que ciertas acciones sean permitidas vía JACC, y autorizadas vía
+ JAAS. Esta en una funcionalidad opcional construída encima de la arquitectura de eventos.
+ </para>
+
+ <para>
+ Primero, debes configurar los oyentes de eventos apropiados, para habilitar el uso de
+ autorización JAAS.
+ </para>
+
+ <programlisting><![CDATA[<listener type="pre-delete" class="org.hibernate.secure.JACCPreDeleteEventListener"/>
+<listener type="pre-update" class="org.hibernate.secure.JACCPreUpdateEventListener"/>
+<listener type="pre-insert" class="org.hibernate.secure.JACCPreInsertEventListener"/>
+<listener type="pre-load" class="org.hibernate.secure.JACCPreLoadEventListener"/>]]></programlisting>
+
+ <para>
+ Seguido, aún en <literal>hibernate.cfg.xml</literal>, liga los permisos a roles:
+ </para>
+
+ <programlisting><![CDATA[<grant role="admin" entity-name="User" actions="insert,update,read"/>
+<grant role="su" entity-name="User" actions="*"/>]]></programlisting>
+
+ <para>
+ Los nombres de role son los roles entendidos por tu proveedor de JACC.
+ </para>
+
+ </sect1>
+
+</chapter>
+
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/content/example_mappings.xml (from rev 12794, core/trunk/documentation/manual/es-ES/src/main/docbook/modules/example_mappings.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/example_mappings.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/example_mappings.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,654 @@
+<chapter id="example-mappings">
+ <title>Ejemplo: Varios Mapeos</title>
+
+ <para>
+ Este capítulo muestra mapeos de asociaciones más complejos.
+ </para>
+
+ <sect1 id="example-mappings-emp">
+ <title>Empleador/Empleado</title>
+
+ <para>
+ El siguiente modelo de la relación entre <literal>Employer</literal> y <literal>Employee</literal>
+ usa una clase de entidad real (<literal>Employment</literal>) para representar la asociación.
+ Esto se ha hecho esto porque podría haber más de un período de empleo para los mismos dos participantes.
+ Se usan componentes para modelar valores monetarios y nombres de empleado.
+ </para>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="../images/EmployerEmployee.gif" format="GIF" align="center"/>
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="../images/EmployerEmployee.gif" format="GIF" align="center"/>
+ </imageobject>
+ </mediaobject>
+
+ <para>
+ He aquí un documento de mapeo posible:
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Employer" table="employers">
+ <id name="id">
+ <generator class="sequence">
+ <param name="sequence">employer_id_seq</param>
+ </generator>
+ </id>
+ <property name="name"/>
+ </class>
+
+ <class name="Employment" table="employment_periods">
+
+ <id name="id">
+ <generator class="sequence">
+ <param name="sequence">employment_id_seq</param>
+ </generator>
+ </id>
+ <property name="startDate" column="start_date"/>
+ <property name="endDate" column="end_date"/>
+
+ <component name="hourlyRate" class="MonetaryAmount">
+ <property name="amount">
+ <column name="hourly_rate" sql-type="NUMERIC(12, 2)"/>
+ </property>
+ <property name="currency" length="12"/>
+ </component>
+
+ <many-to-one name="employer" column="employer_id" not-null="true"/>
+ <many-to-one name="employee" column="employee_id" not-null="true"/>
+
+ </class>
+
+ <class name="Employee" table="employees">
+ <id name="id">
+ <generator class="sequence">
+ <param name="sequence">employee_id_seq</param>
+ </generator>
+ </id>
+ <property name="taxfileNumber"/>
+ <component name="name" class="Name">
+ <property name="firstName"/>
+ <property name="initial"/>
+ <property name="lastName"/>
+ </component>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Y he aquí el esquema de tablas generado por <literal>SchemaExport</literal>.
+ </para>
+
+ <programlisting><![CDATA[create table employers (
+ id BIGINT not null,
+ name VARCHAR(255),
+ primary key (id)
+)
+
+create table employment_periods (
+ id BIGINT not null,
+ hourly_rate NUMERIC(12, 2),
+ currency VARCHAR(12),
+ employee_id BIGINT not null,
+ employer_id BIGINT not null,
+ end_date TIMESTAMP,
+ start_date TIMESTAMP,
+ primary key (id)
+)
+
+create table employees (
+ id BIGINT not null,
+ firstName VARCHAR(255),
+ initial CHAR(1),
+ lastName VARCHAR(255),
+ taxfileNumber VARCHAR(255),
+ primary key (id)
+)
+
+alter table employment_periods
+ add constraint employment_periodsFK0 foreign key (employer_id) references employers
+alter table employment_periods
+ add constraint employment_periodsFK1 foreign key (employee_id) references employees
+create sequence employee_id_seq
+create sequence employment_id_seq
+create sequence employer_id_seq]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="example-mappings-authorwork">
+ <title>Autor/Obra</title>
+
+ <para>
+ Considera el siguiente modelo de las relaciones entre <literal>Work</literal>,
+ <literal>Author</literal> y <literal>Person</literal>. Representamos la relación entre <literal>Work</literal>
+ y <literal>Author</literal> como una asociación muchos-a-muchos. Elegimos representar la relación entre
+ <literal>Author</literal> y <literal>Person</literal> como una asociación uno-a-uno. Otra posibilidad
+ hubiese sido que <literal>Author</literal> extendiera <literal>Person</literal>.
+ </para>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="../images/AuthorWork.gif" format="GIF" align="center"/>
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="../images/AuthorWork.gif" format="GIF" align="center"/>
+ </imageobject>
+ </mediaobject>
+
+ <para>
+ El siguiente documento de mapeo representa estas relaciones correctamente:
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Work" table="works" discriminator-value="W">
+
+ <id name="id" column="id">
+ <generator class="native"/>
+ </id>
+ <discriminator column="type" type="character"/>
+
+ <property name="title"/>
+ <set name="authors" table="author_work">
+ <key column name="work_id"/>
+ <many-to-many class="Author" column name="author_id"/>
+ </set>
+
+ <subclass name="Book" discriminator-value="B">
+ <property name="text"/>
+ </subclass>
+
+ <subclass name="Song" discriminator-value="S">
+ <property name="tempo"/>
+ <property name="genre"/>
+ </subclass>
+
+ </class>
+
+ <class name="Author" table="authors">
+
+ <id name="id" column="id">
+ <!-- The Author must have the same identifier as the Person -->
+ <generator class="assigned"/>
+ </id>
+
+ <property name="alias"/>
+ <one-to-one name="person" constrained="true"/>
+
+ <set name="works" table="author_work" inverse="true">
+ <key column="author_id"/>
+ <many-to-many class="Work" column="work_id"/>
+ </set>
+
+ </class>
+
+ <class name="Person" table="persons">
+ <id name="id" column="id">
+ <generator class="native"/>
+ </id>
+ <property name="name"/>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Hay cuatro tablas en este mapeo. <literal>works</literal>, <literal>authors</literal> y <literal>persons</literal>
+ tienen los datos de obra, autor y persona respectivamente. <literal>author_work</literal> es una tabla de
+ asociación enlazando autores a obras. He aquí el esquema de tablas, tal como fue generado por
+ <literal>SchemaExport</literal>.
+ </para>
+
+ <programlisting><![CDATA[create table works (
+ id BIGINT not null generated by default as identity,
+ tempo FLOAT,
+ genre VARCHAR(255),
+ text INTEGER,
+ title VARCHAR(255),
+ type CHAR(1) not null,
+ primary key (id)
+)
+
+create table author_work (
+ author_id BIGINT not null,
+ work_id BIGINT not null,
+ primary key (work_id, author_id)
+)
+
+create table authors (
+ id BIGINT not null generated by default as identity,
+ alias VARCHAR(255),
+ primary key (id)
+)
+
+create table persons (
+ id BIGINT not null generated by default as identity,
+ name VARCHAR(255),
+ primary key (id)
+)
+
+alter table authors
+ add constraint authorsFK0 foreign key (id) references persons
+alter table author_work
+ add constraint author_workFK0 foreign key (author_id) references authors
+alter table author_work
+ add constraint author_workFK1 foreign key (work_id) references works]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="example-mappings-customerorderproduct">
+ <title>Cliente/Orden/Producto</title>
+
+ <para>
+ Ahora considera un modelo de las relaciones entre <literal>Customer</literal>,
+ <literal>Order</literal> y <literal>LineItem</literal> y <literal>Product</literal>.
+ Hay una asociación uno-a-muchos entre <literal>Customer</literal> y <literal>Order</literal>,
+ pero, ¿cómo deberíamos representar <literal>Order</literal> / <literal>LineItem</literal> / <literal>Product</literal>?
+ He elegido mapear <literal>LineItem</literal> como una clase de asociación representando la
+ asociación muchos-a-muchos entre <literal>Order</literal> y <literal>Product</literal>. En Hibernate,
+ esto se llama un elemento compuesto.
+ </para>
+
+ <mediaobject>
+ <imageobject role="fo">
+ <imagedata fileref="../images/CustomerOrderProduct.gif" format="GIF" align="center"/>
+ </imageobject>
+ <imageobject role="html">
+ <imagedata fileref="../images/CustomerOrderProduct.gif" format="GIF" align="center"/>
+ </imageobject>
+ </mediaobject>
+
+ <para>
+ El documento de mapeo:
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Customer" table="customers">
+ <id name="id">
+ <generator class="native"/>
+ </id>
+ <property name="name"/>
+ <set name="orders" inverse="true">
+ <key column="customer_id"/>
+ <one-to-many class="Order"/>
+ </set>
+ </class>
+
+ <class name="Order" table="orders">
+ <id name="id">
+ <generator class="native"/>
+ </id>
+ <property name="date"/>
+ <many-to-one name="customer" column="customer_id"/>
+ <list name="lineItems" table="line_items">
+ <key column="order_id"/>
+ <list-index column="line_number"/>
+ <composite-element class="LineItem">
+ <property name="quantity"/>
+ <many-to-one name="product" column="product_id"/>
+ </composite-element>
+ </list>
+ </class>
+
+ <class name="Product" table="products">
+ <id name="id">
+ <generator class="native"/>
+ </id>
+ <property name="serialNumber"/>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ <literal>customers</literal>, <literal>orders</literal>, <literal>line_items</literal> y
+ <literal>products</literal> tienen los datos de cliente, orden, ítem de línea de orden y producto
+ respectivamente. Además <literal>line_items</literal> actúa como una tabla de asociación enlazando
+ órdenes con productos.
+ </para>
+
+ <programlisting><![CDATA[create table customers (
+ id BIGINT not null generated by default as identity,
+ name VARCHAR(255),
+ primary key (id)
+)
+
+create table orders (
+ id BIGINT not null generated by default as identity,
+ customer_id BIGINT,
+ date TIMESTAMP,
+ primary key (id)
+)
+
+create table line_items (
+ line_number INTEGER not null,
+ order_id BIGINT not null,
+ product_id BIGINT,
+ quantity INTEGER,
+ primary key (order_id, line_number)
+)
+
+create table products (
+ id BIGINT not null generated by default as identity,
+ serialNumber VARCHAR(255),
+ primary key (id)
+)
+
+alter table orders
+ add constraint ordersFK0 foreign key (customer_id) references customers
+alter table line_items
+ add constraint line_itemsFK0 foreign key (product_id) references products
+alter table line_items
+ add constraint line_itemsFK1 foreign key (order_id) references orders]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="misc">
+ <title>Mapeos misceláneos de ejemplo</title>
+
+ <para>
+ Todos estos ejemplos están tomados de la batería de pruebas de Hibernate.
+ Encontrarás muchos otros mapeos de ejemplo útiles allí. Mira en la carpeta
+ <literal>test</literal> de la distribución de Hibernate.
+ </para>
+
+ <para>POR HACER: poner palabras alrededor de este material</para>
+
+ <sect2 id="example-mappings-typed-onetone">
+ <title>Asociación uno-a-uno "Tipificada"</title>
+<programlisting><![CDATA[<class name="Person">
+ <id name="name"/>
+ <one-to-one name="address"
+ cascade="all">
+ <formula>name</formula>
+ <formula>'HOME'</formula>
+ </one-to-one>
+ <one-to-one name="mailingAddress"
+ cascade="all">
+ <formula>name</formula>
+ <formula>'MAILING'</formula>
+ </one-to-one>
+</class>
+
+<class name="Address" batch-size="2"
+ check="addressType in ('MAILING', 'HOME', 'BUSINESS')">
+ <composite-id>
+ <key-many-to-one name="person"
+ column="personName"/>
+ <key-property name="type"
+ column="addressType"/>
+ </composite-id>
+ <property name="street" type="text"/>
+ <property name="state"/>
+ <property name="zip"/>
+</class>]]></programlisting>
+ </sect2>
+
+ <sect2 id="example-mappings-composite-key">
+ <title>Ejemplo de clave compuesta</title>
+<programlisting><![CDATA[<class name="Customer">
+
+ <id name="customerId"
+ length="10">
+ <generator class="assigned"/>
+ </id>
+
+ <property name="name" not-null="true" length="100"/>
+ <property name="address" not-null="true" length="200"/>
+
+ <list name="orders"
+ inverse="true"
+ cascade="save-update">
+ <key column="customerId"/>
+ <index column="orderNumber"/>
+ <one-to-many class="Order"/>
+ </list>
+
+</class>
+
+<class name="Order" table="CustomerOrder" lazy="true">
+ <synchronize table="LineItem"/>
+ <synchronize table="Product"/>
+
+ <composite-id name="id"
+ class="Order$Id">
+ <key-property name="customerId" length="10"/>
+ <key-property name="orderNumber"/>
+ </composite-id>
+
+ <property name="orderDate"
+ type="calendar_date"
+ not-null="true"/>
+
+ <property name="total">
+ <formula>
+ ( select sum(li.quantity*p.price)
+ from LineItem li, Product p
+ where li.productId = p.productId
+ and li.customerId = customerId
+ and li.orderNumber = orderNumber )
+ </formula>
+ </property>
+
+ <many-to-one name="customer"
+ column="customerId"
+ insert="false"
+ update="false"
+ not-null="true"/>
+
+ <bag name="lineItems"
+ fetch="join"
+ inverse="true"
+ cascade="save-update">
+ <key>
+ <column name="customerId"/>
+ <column name="orderNumber"/>
+ </key>
+ <one-to-many class="LineItem"/>
+ </bag>
+
+</class>
+
+<class name="LineItem">
+
+ <composite-id name="id"
+ class="LineItem$Id">
+ <key-property name="customerId" length="10"/>
+ <key-property name="orderNumber"/>
+ <key-property name="productId" length="10"/>
+ </composite-id>
+
+ <property name="quantity"/>
+
+ <many-to-one name="order"
+ insert="false"
+ update="false"
+ not-null="true">
+ <column name="customerId"/>
+ <column name="orderNumber"/>
+ </many-to-one>
+
+ <many-to-one name="product"
+ insert="false"
+ update="false"
+ not-null="true"
+ column="productId"/>
+
+</class>
+
+<class name="Product">
+ <synchronize table="LineItem"/>
+
+ <id name="productId"
+ length="10">
+ <generator class="assigned"/>
+ </id>
+
+ <property name="description"
+ not-null="true"
+ length="200"/>
+ <property name="price" length="3"/>
+ <property name="numberAvailable"/>
+
+ <property name="numberOrdered">
+ <formula>
+ ( select sum(li.quantity)
+ from LineItem li
+ where li.productId = productId )
+ </formula>
+ </property>
+
+</class>]]></programlisting>
+ </sect2>
+
+ <sect2 id="example-mappings-composite-key-manytomany">
+ <title>Muchos-a-muchos con atributo de clave compuesta compartido</title>
+<programlisting><![CDATA[<class name="User" table="`User`">
+ <composite-id>
+ <key-property name="name"/>
+ <key-property name="org"/>
+ </composite-id>
+ <set name="groups" table="UserGroup">
+ <key>
+ <column name="userName"/>
+ <column name="org"/>
+ </key>
+ <many-to-many class="Group">
+ <column name="groupName"/>
+ <formula>org</formula>
+ </many-to-many>
+ </set>
+</class>
+
+<class name="Group" table="`Group`">
+ <composite-id>
+ <key-property name="name"/>
+ <key-property name="org"/>
+ </composite-id>
+ <property name="description"/>
+ <set name="users" table="UserGroup" inverse="true">
+ <key>
+ <column name="groupName"/>
+ <column name="org"/>
+ </key>
+ <many-to-many class="User">
+ <column name="userName"/>
+ <formula>org</formula>
+ </many-to-many>
+ </set>
+</class>
+]]></programlisting>
+ </sect2>
+
+ <sect2 id="example-mappings-content-discrimination">
+ <title>Discriminación basada en contenido</title>
+<programlisting><![CDATA[<class name="Person"
+ discriminator-value="P">
+
+ <id name="id"
+ column="person_id"
+ unsaved-value="0">
+ <generator class="native"/>
+ </id>
+
+
+ <discriminator
+ type="character">
+ <formula>
+ case
+ when title is not null then 'E'
+ when salesperson is not null then 'C'
+ else 'P'
+ end
+ </formula>
+ </discriminator>
+
+ <property name="name"
+ not-null="true"
+ length="80"/>
+
+ <property name="sex"
+ not-null="true"
+ update="false"/>
+
+ <component name="address">
+ <property name="address"/>
+ <property name="zip"/>
+ <property name="country"/>
+ </component>
+
+ <subclass name="Employee"
+ discriminator-value="E">
+ <property name="title"
+ length="20"/>
+ <property name="salary"/>
+ <many-to-one name="manager"/>
+ </subclass>
+
+ <subclass name="Customer"
+ discriminator-value="C">
+ <property name="comments"/>
+ <many-to-one name="salesperson"/>
+ </subclass>
+
+</class>]]></programlisting>
+ </sect2>
+
+ <sect2 id="example-mappings-association-alternatekeys" >
+ <title>Asociaciones sobre claves alternativas</title>
+<programlisting><![CDATA[<class name="Person">
+
+ <id name="id">
+ <generator class="hilo"/>
+ </id>
+
+ <property name="name" length="100"/>
+
+ <one-to-one name="address"
+ property-ref="person"
+ cascade="all"
+ fetch="join"/>
+
+ <set name="accounts"
+ inverse="true">
+ <key column="userId"
+ property-ref="userId"/>
+ <one-to-many class="Account"/>
+ </set>
+
+ <property name="userId" length="8"/>
+
+</class>
+
+<class name="Address">
+
+ <id name="id">
+ <generator class="hilo"/>
+ </id>
+
+ <property name="address" length="300"/>
+ <property name="zip" length="5"/>
+ <property name="country" length="25"/>
+ <many-to-one name="person" unique="true" not-null="true"/>
+
+</class>
+
+<class name="Account">
+ <id name="accountId" length="32">
+ <generator class="uuid.hex"/>
+ </id>
+
+ <many-to-one name="user"
+ column="userId"
+ property-ref="userId"/>
+
+ <property name="type" not-null="true"/>
+
+</class>]]></programlisting>
+ </sect2>
+
+ </sect1>
+
+</chapter>
+
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/content/example_parentchild.xml (from rev 12794, core/trunk/documentation/manual/es-ES/src/main/docbook/modules/example_parentchild.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/example_parentchild.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/example_parentchild.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,362 @@
+<chapter id="example-parentchild">
+ <title>Ejemplo: Padre/Hijo</title>
+
+ <para>
+ Una de las primerísimas cosas que los usuarios nuevos intentan hacer con Hibernate es modelar una relación de
+ tipo padre / hijo. Para esto hay dos enfoques diferentes. Por varias razones, el enfoque más conveniente,
+ especialmente para usuarios nuevos, es modelar tanto <literal>Parent</literal> como <literal>Child</literal>
+ como clases de entidad con una asociación <literal><one-to-many></literal> desde <literal>Parent</literal>
+ a <literal>Child</literal>. (El enfoque alternativo es declarar el <literal>Child</literal> como un
+ <literal><composite-element></literal>.) Ahora, resulta que la semántica por defecto de una asociación
+ uno a muchos (en Hibernate) es mucho menos cercana a la semántica usual de una relación padre / hijo que aquellas
+ de un mapeo de elementos compuestos. Explicaremos cómo usar una <emphasis>asociación uno a muchos bidireccional
+ con tratamiento en cascada</emphasis> para modelar una relación padre / hijo eficiente y elegantemente.
+ ¡No es para nada difícil!
+ </para>
+
+ <sect1 id="example-parentchild-collections">
+ <title>Una nota sobre las colecciones</title>
+
+ <para>
+ Se considera que las colecciones de Hibernate son una parte lógica de la entidad que las posee; nunca de
+ las entidades contenidas. ¡Esta es una distinción crucial! Esto tiene las siguientes consecuencias:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ Cuando se quita / añade un objeto desde / a una colección, se incrementa el número de versión del
+ dueño de la colección.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Si un objeto que fue quitado de una colección es una instancia de un tipo de valor (por ejemplo, un
+ elemento compuesto), ese objeta cesará de ser persistente y su estado será completamente quitado de la
+ base de datos. Asimismo, añadir una instancia de tipo de valor a la colección causará que su estado
+ sea inmediatamente persistente.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Por otro lado, si se quita una entidad de una colección (una asociación uno-a-muchos o muchos-a-muchos),
+ no será borrado, por defecto. Este comportamiento es completamente consistente. ¡Un cambio en el
+ estado interno de otra entidad no hace desaparecer la entidad asociada! Asimismo, añadir una entidad a
+ una colección no causa que la entidad se vuelva persistente, por defecto.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ En cambio, el comportamiento por defecto es que al añadir una entidad a una colección se crea meramente
+ un enlace entre las dos entidades, mientras que al quitarla se quita el enlace. Esto es muy apropiado para
+ todos los tipos de casos. Donde no es para nada apropiado es en el caso de una relación padre / hijo. donde
+ la vida del hijo está ligada al ciclo de vida del padre.
+ </para>
+
+ </sect1>
+
+ <sect1 id="example-parentchild-bidir">
+ <title>Uno-a-muchos bidirectional</title>
+
+ <para>
+ Supón que empezamos con una asociación simple <literal><one-to-many></literal> desde
+ <literal>Parent</literal> a <literal>Child</literal>.
+ </para>
+
+ <programlisting><![CDATA[<set name="children">
+ <key column="parent_id"/>
+ <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+ <para>
+ Si ejecutásemos el siguiente código
+ </para>
+
+ <programlisting><![CDATA[Parent p = .....;
+Child c = new Child();
+p.getChildren().add(c);
+session.save(c);
+session.flush();]]></programlisting>
+
+ <para>
+ Hibernate publicaría dos sentencias SQL:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>un <literal>INSERT</literal> para crear el registro de <literal>c</literal></para>
+ </listitem>
+ <listitem>
+ <para>
+ un <literal>UPDATE</literal> para crear el enlace desde <literal>p</literal> a
+ <literal>c</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Esto no es sólo ineficiente, sino que además viola cualquier restricción <literal>NOT NULL</literal> en la
+ columna <literal>parent_id</literal>. Podemos reparar la violación de restricción de nulabilidad
+ especificando <literal>not-null="true"</literal> en el mapeo de la colección:
+ </para>
+
+ <programlisting><![CDATA[<set name="children">
+ <key column="parent_id" not-null="true"/>
+ <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+ <para>
+ Sin embargo, esta no es la solución recomendada.
+ </para>
+ <para>
+ El caso subyacente de este comportamiento es que el enlace (la clave foránea <literal>parent_id</literal>)
+ de <literal>p</literal> a <literal>c</literal> no es considerado parte del estado del objeto
+ <literal>Child</literal> y por lo tanto no es creada en el <literal>INSERT</literal>. De modo que la
+ solución es hacer el enlace parte del mapeo del <literal>Child</literal>.
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="parent" column="parent_id" not-null="true"/>]]></programlisting>
+
+ <para>
+ (Necesitamos además añadir la propiedad <literal>parent</literal> a la clase <literal>Child</literal>.)
+ </para>
+
+ <para>
+ Ahora que la entidad <literal>Child</literal> está gestionando el estado del enlace, le decimos a la
+ colección que no actualice el enlace. Usamos el atributo <literal>inverse</literal>.
+ </para>
+
+ <programlisting><![CDATA[<set name="children" inverse="true">
+ <key column="parent_id"/>
+ <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+ <para>
+ El siguiente código podría ser usado para añadir un nuevo <literal>Child</literal>
+ </para>
+
+ <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+c.setParent(p);
+p.getChildren().add(c);
+session.save(c);
+session.flush();]]></programlisting>
+
+ <para>
+ Y ahora, ¡Sólo se publicaría un <literal>INSERT</literal> de SQL!
+ </para>
+
+ <para>
+ Para ajustar un poco más las cosas, podríamos crear un método <literal>addChild()</literal> en
+ <literal>Parent</literal>.
+ </para>
+
+ <programlisting><![CDATA[public void addChild(Child c) {
+ c.setParent(this);
+ children.add(c);
+}]]></programlisting>
+
+ <para>
+ Ahora, el código para añadir un <literal>Child</literal> se ve así
+ </para>
+
+ <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+p.addChild(c);
+session.save(c);
+session.flush();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="example-parentchild-cascades">
+ <title>Ciclo de vida en cascada</title>
+
+ <para>
+ La llamada explícita a <literal>save()</literal> es aún molesta. Apuntaremos a esto usando tratamientos
+ en cascada.
+ </para>
+
+ <programlisting><![CDATA[<set name="children" inverse="true" cascade="all">
+ <key column="parent_id"/>
+ <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+ <para>
+ Esto simplifica el código anterior a
+ </para>
+
+ <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = new Child();
+p.addChild(c);
+session.flush();]]></programlisting>
+
+ <para>
+ Similarmente, no necesitamos iterar los hijos al salvar o borrar un <literal>Parent</literal>.
+ Lo siguiente quita <literal>p</literal> y todos sus hijos de la base de datos.
+ </para>
+
+ <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+session.delete(p);
+session.flush();]]></programlisting>
+
+ <para>
+ Sin embargo, este código
+ </para>
+
+ <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = (Child) p.getChildren().iterator().next();
+p.getChildren().remove(c);
+c.setParent(null);
+session.flush();]]></programlisting>
+
+ <para>
+ no quitará <literal>c</literal> de la base de datos; sólo quitará el enlace a <literal>p</literal>
+ (y causará una violación a una restricción <literal>NOT NULL</literal>). Necesitas borrar el hijo
+ explícitamente llamando a <literal>delete()</literal>.
+ </para>
+
+ <programlisting><![CDATA[Parent p = (Parent) session.load(Parent.class, pid);
+Child c = (Child) p.getChildren().iterator().next();
+p.getChildren().remove(c);
+session.delete(c);
+session.flush();]]></programlisting>
+
+ <para>
+ Ahora, en nuestro caso, un <literal>Child</literal> no puede existir realmente sin su padre. De modo que
+ si quitamos un <literal>Child</literal> de la colección, realmente queremos que sea borrado. Para esto,
+ debemos usar <literal>cascade="all-delete-orphan"</literal>.
+ </para>
+
+ <programlisting><![CDATA[<set name="children" inverse="true" cascade="all-delete-orphan">
+ <key column="parent_id"/>
+ <one-to-many class="Child"/>
+</set>]]></programlisting>
+
+ <para>
+ Nota: aunque el mapeo de la colección especifique <literal>inverse="true"</literal>, el tratamiento en
+ cascada se procesa aún al iterar los elementos de colección. De modo que si requieres que un objeto sea
+ salvado, borrado o actualizado en cascada, debes añadirlo a la colección. No es suficiente con simplemente
+ llamar a <literal>setParent()</literal>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="example-parentchild-update">
+ <title>Tratamiento en cascada y <literal>unsaved-value</literal></title>
+
+ <para>
+ Supón que hemos cargado un <literal>Parent</literal> en una <literal>Session</literal>, hemos hecho algunos
+ cambios en una acción de UI y deseamos hacer persistentes estos cambios en una nueva sesión llamando a
+ <literal>update()</literal>. El <literal>Parent</literal> contendrá una colección de hijos y, ya que
+ está habilitado el tratamiento en cascada, Hibernate necesita saber qué hijos están recién instanciados
+ y cuáles representan filas existentes en la base de datos. Asumamos que tanto <literal>Parent</literal> como
+ <literal>Child</literal> tienen propiedades identificadoras generadas de tipo <literal>Long</literal>.
+ Hibernate usará el identificador y el valor de la propiedad de versión/timestamp para determinar cuáles de
+ los hijos son nuevos. (Ver <xref linkend="objectstate-saveorupdate"/>.) <emphasis>En Hibernate3, no es
+ más necesario especificar un <literal>unsaved-value</literal> explícitamente.</emphasis>
+ </para>
+
+ <para>
+ The following code will update <literal>parent</literal> and <literal>child</literal> and insert
+ <literal>newChild</literal>.
+ </para>
+
+ <programlisting><![CDATA[//parent and child were both loaded in a previous session
+parent.addChild(child);
+Child newChild = new Child();
+parent.addChild(newChild);
+session.update(parent);
+session.flush();]]></programlisting>
+
+ <para>
+ Bueno, todo eso está muy bien para el caso de un identificador generado, pero ¿qué de los
+ identificadores asignados y de los identificadores compuestos? Esto es más difícil, ya que Hibernate
+ no puede usar la propiedad identificadora para distinguir entre un objeto recién instanciado (con un
+ identificador asignado por el usuario) y un objeto cargado en una sesión previa. En este caso, Hibernate
+ bien usará la propiedad de versión o timestamp, o bien consultará realmente el caché de segundo nivel,
+ o bien, en el peor de los casos, la base de datos, para ver si existe la fila.
+ </para>
+
+ <!-- undocumenting
+ <para>
+ There is one further possibility. The <literal>Interceptor</literal> method named
+ <literal>isUnsaved()</literal> lets the application implement its own strategy for distinguishing
+ newly instantiated objects. For example, you could define a base class for your persistent classes.
+ </para>
+
+ <programlisting><![CDATA[public class Persistent {
+ private boolean _saved = false;
+ public void onSave() {
+ _saved=true;
+ }
+ public void onLoad() {
+ _saved=true;
+ }
+ ......
+ public boolean isSaved() {
+ return _saved;
+ }
+}]]></programlisting>
+
+ <para>
+ (The <literal>saved</literal> property is non-persistent.)
+ Now implement <literal>isUnsaved()</literal>, along with <literal>onLoad()</literal>
+ and <literal>onSave()</literal> as follows.
+ </para>
+
+ <programlisting><![CDATA[public Boolean isUnsaved(Object entity) {
+ if (entity instanceof Persistent) {
+ return new Boolean( !( (Persistent) entity ).isSaved() );
+ }
+ else {
+ return null;
+ }
+}
+
+public boolean onLoad(Object entity,
+ Serializable id,
+ Object[] state,
+ String[] propertyNames,
+ Type[] types) {
+
+ if (entity instanceof Persistent) ( (Persistent) entity ).onLoad();
+ return false;
+}
+
+public boolean onSave(Object entity,
+ Serializable id,
+ Object[] state,
+ String[] propertyNames,
+ Type[] types) {
+
+ if (entity instanceof Persistent) ( (Persistent) entity ).onSave();
+ return false;
+}]]></programlisting>
+
+ <para>
+ Don't worry; in Hibernate3 you don't need to write any of this kind of code if you don't want to.
+ </para>
+ -->
+ </sect1>
+
+ <sect1 id="example-parentchild-conclusion">
+ <title>Conclusión</title>
+
+ <para>
+ Hay que resumir un poco aquí y podría parecer confuso a la primera vez. Sin embargo, en la práctica,
+ todo funciona muy agradablemente. La mayoría de las aplicaciones de Hibernate usan el patrón
+ padre / hijo en muchos sitios.
+ </para>
+
+ <para>
+ Hemos mencionado una alternativa en el primer párrafo. Ninguno de los temas anteriores existe en el caso
+ de los mapeos <literal><composite-element></literal>, que tienen exactamente la semántica de una
+ relación padre / hijo. Desafortunadamente, hay dos grandes limitaciones para las clases de elementos
+ compuestos: los elementos compuestos no pueden poseer sus propias colecciones, y no deben ser el hijo
+ de cualquier otra entidad que no sea su padre único.
+ </para>
+
+ </sect1>
+
+</chapter>
\ No newline at end of file
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/content/example_weblog.xml (from rev 12794, core/trunk/documentation/manual/es-ES/src/main/docbook/modules/example_weblog.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/example_weblog.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/example_weblog.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,429 @@
+<chapter id="example-weblog">
+ <title>Ejemplo: Aplicación de Weblog</title>
+
+ <sect1 id="example-weblog-classes">
+ <title>Clases Persistentes</title>
+
+ <para>
+ Las clases persistentes representan un weblog, y un ítem enviado a un weblog. Van a ser modelados como una
+ relación padre/hijo estñndar, pero usaremos un bag ordenado, en vez de un conjunto (set).
+ </para>
+
+ <programlisting><![CDATA[package eg;
+
+import java.util.List;
+
+public class Blog {
+ private Long _id;
+ private String _name;
+ private List _items;
+
+ public Long getId() {
+ return _id;
+ }
+ public List getItems() {
+ return _items;
+ }
+ public String getName() {
+ return _name;
+ }
+ public void setId(Long long1) {
+ _id = long1;
+ }
+ public void setItems(List list) {
+ _items = list;
+ }
+ public void setName(String string) {
+ _name = string;
+ }
+}]]></programlisting>
+
+ <programlisting><![CDATA[package eg;
+
+import java.text.DateFormat;
+import java.util.Calendar;
+
+public class BlogItem {
+ private Long _id;
+ private Calendar _datetime;
+ private String _text;
+ private String _title;
+ private Blog _blog;
+
+ public Blog getBlog() {
+ return _blog;
+ }
+ public Calendar getDatetime() {
+ return _datetime;
+ }
+ public Long getId() {
+ return _id;
+ }
+ public String getText() {
+ return _text;
+ }
+ public String getTitle() {
+ return _title;
+ }
+ public void setBlog(Blog blog) {
+ _blog = blog;
+ }
+ public void setDatetime(Calendar calendar) {
+ _datetime = calendar;
+ }
+ public void setId(Long long1) {
+ _id = long1;
+ }
+ public void setText(String string) {
+ _text = string;
+ }
+ public void setTitle(String string) {
+ _title = string;
+ }
+}]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="example-weblog-mappings">
+ <title>Mapeos de Hibernate</title>
+
+ <para>
+ Los mapeos XML ahora deben ser absolutamente directos.
+ </para>
+
+ <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+ <class
+ name="Blog"
+ table="BLOGS">
+
+ <id
+ name="id"
+ column="BLOG_ID">
+
+ <generator class="native"/>
+
+ </id>
+
+ <property
+ name="name"
+ column="NAME"
+ not-null="true"
+ unique="true"/>
+
+ <bag
+ name="items"
+ inverse="true"
+ order-by="DATE_TIME"
+ cascade="all">
+
+ <key column="BLOG_ID"/>
+ <one-to-many class="BlogItem"/>
+
+ </bag>
+
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping package="eg">
+
+ <class
+ name="BlogItem"
+ table="BLOG_ITEMS"
+ dynamic-update="true">
+
+ <id
+ name="id"
+ column="BLOG_ITEM_ID">
+
+ <generator class="native"/>
+
+ </id>
+
+ <property
+ name="title"
+ column="TITLE"
+ not-null="true"/>
+
+ <property
+ name="text"
+ column="TEXT"
+ not-null="true"/>
+
+ <property
+ name="datetime"
+ column="DATE_TIME"
+ not-null="true"/>
+
+ <many-to-one
+ name="blog"
+ column="BLOG_ID"
+ not-null="true"/>
+
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="example-weblog-code">
+ <title>Código Hibernate</title>
+
+ <para>
+ La siguiente clase demuestra algunos de los tipos de cosas que podemos haces con estas clases,
+ usando Hibernate.
+ </para>
+
+ <programlisting><![CDATA[package eg;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.HibernateException;
+import org.hibernate.Query;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.tool.hbm2ddl.SchemaExport;
+
+public class BlogMain {
+
+ private SessionFactory _sessions;
+
+ public void configure() throws HibernateException {
+ _sessions = new Configuration()
+ .addClass(Blog.class)
+ .addClass(BlogItem.class)
+ .buildSessionFactory();
+ }
+
+ public void exportTables() throws HibernateException {
+ Configuration cfg = new Configuration()
+ .addClass(Blog.class)
+ .addClass(BlogItem.class);
+ new SchemaExport(cfg).create(true, true);
+ }
+
+ public Blog createBlog(String name) throws HibernateException {
+
+ Blog blog = new Blog();
+ blog.setName(name);
+ blog.setItems( new ArrayList() );
+
+ Session session = _sessions.openSession();
+ Transaction tx = null;
+ try {
+ tx = session.beginTransaction();
+ session.persist(blog);
+ tx.commit();
+ }
+ catch (HibernateException he) {
+ if (tx!=null) tx.rollback();
+ throw he;
+ }
+ finally {
+ session.close();
+ }
+ return blog;
+ }
+
+ public BlogItem createBlogItem(Blog blog, String title, String text)
+ throws HibernateException {
+
+ BlogItem item = new BlogItem();
+ item.setTitle(title);
+ item.setText(text);
+ item.setBlog(blog);
+ item.setDatetime( Calendar.getInstance() );
+ blog.getItems().add(item);
+
+ Session session = _sessions.openSession();
+ Transaction tx = null;
+ try {
+ tx = session.beginTransaction();
+ session.update(blog);
+ tx.commit();
+ }
+ catch (HibernateException he) {
+ if (tx!=null) tx.rollback();
+ throw he;
+ }
+ finally {
+ session.close();
+ }
+ return item;
+ }
+
+ public BlogItem createBlogItem(Long blogid, String title, String text)
+ throws HibernateException {
+
+ BlogItem item = new BlogItem();
+ item.setTitle(title);
+ item.setText(text);
+ item.setDatetime( Calendar.getInstance() );
+
+ Session session = _sessions.openSession();
+ Transaction tx = null;
+ try {
+ tx = session.beginTransaction();
+ Blog blog = (Blog) session.load(Blog.class, blogid);
+ item.setBlog(blog);
+ blog.getItems().add(item);
+ tx.commit();
+ }
+ catch (HibernateException he) {
+ if (tx!=null) tx.rollback();
+ throw he;
+ }
+ finally {
+ session.close();
+ }
+ return item;
+ }
+
+ public void updateBlogItem(BlogItem item, String text)
+ throws HibernateException {
+
+ item.setText(text);
+
+ Session session = _sessions.openSession();
+ Transaction tx = null;
+ try {
+ tx = session.beginTransaction();
+ session.update(item);
+ tx.commit();
+ }
+ catch (HibernateException he) {
+ if (tx!=null) tx.rollback();
+ throw he;
+ }
+ finally {
+ session.close();
+ }
+ }
+
+ public void updateBlogItem(Long itemid, String text)
+ throws HibernateException {
+
+ Session session = _sessions.openSession();
+ Transaction tx = null;
+ try {
+ tx = session.beginTransaction();
+ BlogItem item = (BlogItem) session.load(BlogItem.class, itemid);
+ item.setText(text);
+ tx.commit();
+ }
+ catch (HibernateException he) {
+ if (tx!=null) tx.rollback();
+ throw he;
+ }
+ finally {
+ session.close();
+ }
+ }
+
+ public List listAllBlogNamesAndItemCounts(int max)
+ throws HibernateException {
+
+ Session session = _sessions.openSession();
+ Transaction tx = null;
+ List result = null;
+ try {
+ tx = session.beginTransaction();
+ Query q = session.createQuery(
+ "select blog.id, blog.name, count(blogItem) " +
+ "from Blog as blog " +
+ "left outer join blog.items as blogItem " +
+ "group by blog.name, blog.id " +
+ "order by max(blogItem.datetime)"
+ );
+ q.setMaxResults(max);
+ result = q.list();
+ tx.commit();
+ }
+ catch (HibernateException he) {
+ if (tx!=null) tx.rollback();
+ throw he;
+ }
+ finally {
+ session.close();
+ }
+ return result;
+ }
+
+ public Blog getBlogAndAllItems(Long blogid)
+ throws HibernateException {
+
+ Session session = _sessions.openSession();
+ Transaction tx = null;
+ Blog blog = null;
+ try {
+ tx = session.beginTransaction();
+ Query q = session.createQuery(
+ "from Blog as blog " +
+ "left outer join fetch blog.items " +
+ "where blog.id = :blogid"
+ );
+ q.setParameter("blogid", blogid);
+ blog = (Blog) q.uniqueResult();
+ tx.commit();
+ }
+ catch (HibernateException he) {
+ if (tx!=null) tx.rollback();
+ throw he;
+ }
+ finally {
+ session.close();
+ }
+ return blog;
+ }
+
+ public List listBlogsAndRecentItems() throws HibernateException {
+
+ Session session = _sessions.openSession();
+ Transaction tx = null;
+ List result = null;
+ try {
+ tx = session.beginTransaction();
+ Query q = session.createQuery(
+ "from Blog as blog " +
+ "inner join blog.items as blogItem " +
+ "where blogItem.datetime > :minDate"
+ );
+
+ Calendar cal = Calendar.getInstance();
+ cal.roll(Calendar.MONTH, false);
+ q.setCalendar("minDate", cal);
+
+ result = q.list();
+ tx.commit();
+ }
+ catch (HibernateException he) {
+ if (tx!=null) tx.rollback();
+ throw he;
+ }
+ finally {
+ session.close();
+ }
+ return result;
+ }
+}]]></programlisting>
+
+ </sect1>
+
+</chapter>
+
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/content/filters.xml (from rev 12794, core/trunk/documentation/manual/es-ES/src/main/docbook/modules/filters.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/filters.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/filters.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,130 @@
+<chapter id="filters">
+ <title>Filtrando datos</title>
+
+ <para>
+ Hibernate3 provee un nuevo enfoque innovador para manejar datos con reglas de "visibilidad".
+ Un <emphasis>filtro de Hibernate</emphasis> es un filtro global, con nombre y parametrizado
+ que puede ser habilitado o deshabilitado para una sesión de Hibernate en particular.
+ </para>
+
+ <sect1 id="objectstate-filters">
+ <title>Filtros de Hibernate</title>
+
+ <para>
+ Hibernate3 añade la habilidad de predefinir criterios de filtros y unir esos filtros tanto a
+ nivel de una clase como de una colección. Un criterio de filtro es la habilidad de definir una
+ cláusula de restricción muy similar al atributo existente "where" disponible en el elemento
+ class y varios elementos de colección. Excepto en que estos filtros pueden ser parametrizados.
+ La aplicación puede tomar la decisión en tiempo de ejecución de qué filtros deben estar
+ habilitados y cuáles deben ser sus parámetros. Los filtros pueden ser usados como vistas de
+ base de datos, pero parametrizados dentro de la aplicación.
+ </para>
+
+ <para>
+ Para usar los filtros, éstos deben primero ser definidos y luego unidos a los elementos de mapeo
+ apropiados. Para definir un filtro, usa el elemento <literal><filter-def/></literal> dentro
+ de un elemento <literal><hibernate-mapping/></literal>:
+ </para>
+
+ <programlisting><![CDATA[<filter-def name="myFilter">
+ <filter-param name="myFilterParam" type="string"/>
+</filter-def>]]></programlisting>
+
+ <para>
+ Entonces este filtro puede ser unido a una clase:
+ </para>
+
+ <programlisting><![CDATA[<class name="myClass" ...>
+ ...
+ <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
+</class>]]></programlisting>
+
+ <para>
+ o a una colección:
+ </para>
+
+ <programlisting><![CDATA[<set ...>
+ <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>
+</set>]]></programlisting>
+
+ <para>
+ o incluso a ambos (o muchos de cada uno) al mismo tiempo.
+ </para>
+
+ <para>
+ Los métodos en <literal>Session</literal> son: <literal>enableFilter(String filterName)</literal>,
+ <literal>getEnabledFilter(String filterName)</literal>, y <literal>disableFilter(String filterName)</literal>.
+ Por defecto, los filtros <emphasis>no</emphasis> están habilitados para una sesión dada; deben ser
+ habilitados explícitamente por medio del uso del método <literal>Session.enableFilter()</literal>,
+ que devuelve una instancia de la interface <literal>Filter</literal>. Usando el filtro simple definido
+ arriba, esto se vería así:
+ </para>
+
+ <programlisting><![CDATA[session.enableFilter("myFilter").setParameter("myFilterParam", "some-value");]]></programlisting>
+
+ <para>
+ Nota que los métodos en la interface org.hibernate.Filter permiten el encadenamiento de métodos
+ común en gran parte de Hibernate.
+ </para>
+
+ <para>
+ Un ejemplo completo, usando datos temporales con un patrón efectivo de fechas de registro:
+ </para>
+
+ <programlisting><![CDATA[<filter-def name="effectiveDate">
+ <filter-param name="asOfDate" type="date"/>
+</filter-def>
+
+<class name="Employee" ...>
+...
+ <many-to-one name="department" column="dept_id" class="Department"/>
+ <property name="effectiveStartDate" type="date" column="eff_start_dt"/>
+ <property name="effectiveEndDate" type="date" column="eff_end_dt"/>
+...
+ <!--
+ Note that this assumes non-terminal records have an eff_end_dt set to
+ a max db date for simplicity-sake
+ -->
+ <filter name="effectiveDate"
+ condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
+</class>
+
+<class name="Department" ...>
+...
+ <set name="employees" lazy="true">
+ <key column="dept_id"/>
+ <one-to-many class="Employee"/>
+ <filter name="effectiveDate"
+ condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
+ </set>
+</class>]]></programlisting>
+
+ <para>
+ Entonces, en orden de asegurar que siempre tendrás de vuelta registros actualmente efectivos,
+ simplemente habilita el filtro en la sesión previo a recuperar los datos de empleados:
+ </para>
+
+<programlisting><![CDATA[Session session = ...;
+session.enabledFilter("effectiveDate").setParameter("asOfDate", new Date());
+List results = session.createQuery("from Employee as e where e.salary > :targetSalary")
+ .setLong("targetSalary", new Long(1000000))
+ .list();
+]]></programlisting>
+
+ <para>
+ En el HQL de arriba, aunque sólo hemos mencionado explícitamente una restricción de salario en
+ los resultados, debido al filtro habilitado la consulta sólo devolverá empleados actualmente activos
+ que tengan un salario mayor que un millón de dólares.
+ </para>
+
+ <para>
+ Nota: si planeas usar filtros con unión externa (outer joining) (bien a través de HQL, o bien
+ de recuperación de carga) sé cuidadoso en la dirección de expresión de la condición. Lo más seguro
+ es establecer esto para unión externa izquierda (left outer joining). En general, coloca el primer
+ parámetro seguido del nombre(s) de columna(s) después del operador.
+ </para>
+
+ </sect1>
+
+</chapter>
+
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/content/inheritance_mapping.xml (from rev 12794, core/trunk/documentation/manual/es-ES/src/main/docbook/modules/inheritance_mapping.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/inheritance_mapping.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/inheritance_mapping.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,464 @@
+<chapter id="inheritance">
+ <title>Mapeo de Herencia</title>
+
+ <sect1 id="inheritance-strategies" revision="2">
+ <title>Las Tres Estrategias</title>
+
+ <para>
+ Hibernate soporta las tres estrategias básicas de mapeo de herencia:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ tabla por jerarquía de clases
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ tabla por subclase
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ tabla por clase concreta
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ En adición, Hibernate soporta un cuarto, ligeramente diferente tipo
+ de polimorfismo:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ polimorfismo implícito
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Es posible usar estrategias de mapeo diferentes para diferentes
+ ramificaciones de la misma jerarquía de herencia, y entonces usar
+ polimorfismo implícito para conseguir polimorfismo a través de
+ toda la jerarquía. Sin embargo, Hibernate no soporta la mezcla de
+ mapeos <literal><subclass></literal>,
+ y <literal><joined-subclass></literal>
+ y <literal><union-subclass></literal> bajo el mismo elemento
+ <literal><class></literal> raíz. Es posible mezclar juntas las
+ estrategias de tabla por jerarquía y tabla por subclase, bajo el mismo
+ elemento <literal><class></literal>, combinando los elementos
+ <literal><subclass></literal> y <literal><join></literal>
+ (ver debajo).
+ </para>
+
+ <sect2 id="inheritance-tableperclass" >
+ <title>Tabla por jerarquía de clases</title>
+
+ <para>
+ Supón que tenemos una interface <literal>Payment</literal>, con
+ los implementadores <literal>CreditCardPayment</literal>,
+ <literal>CashPayment</literal>, <literal>ChequePayment</literal>.
+ El mapeo de tabla por jerarquía se vería así:
+ </para>
+
+ <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+ <id name="id" type="long" column="PAYMENT_ID">
+ <generator class="native"/>
+ </id>
+ <discriminator column="PAYMENT_TYPE" type="string"/>
+ <property name="amount" column="AMOUNT"/>
+ ...
+ <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+ <property name="creditCardType" column="CCTYPE"/>
+ ...
+ </subclass>
+ <subclass name="CashPayment" discriminator-value="CASH">
+ ...
+ </subclass>
+ <subclass name="ChequePayment" discriminator-value="CHEQUE">
+ ...
+ </subclass>
+</class>]]></programlisting>
+
+ <para>
+ Se requiere exactamente una tabla. Hay una gran limitación de esta estrategia de mapeo:
+ las columnas declaradas por las subclases, como <literal>CCTYPE</literal>, no pueden
+ tener restricciones <literal>NOT NULL</literal>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="inheritance-tablepersubclass">
+ <title>Tabla por subclase</title>
+
+ <para>
+ Un mapeo de tabla por sublclase se vería así:
+ </para>
+
+ <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+ <id name="id" type="long" column="PAYMENT_ID">
+ <generator class="native"/>
+ </id>
+ <property name="amount" column="AMOUNT"/>
+ ...
+ <joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
+ <key column="PAYMENT_ID"/>
+ <property name="creditCardType" column="CCTYPE"/>
+ ...
+ </joined-subclass>
+ <joined-subclass name="CashPayment" table="CASH_PAYMENT">
+ <key column="PAYMENT_ID"/>
+ ...
+ </joined-subclass>
+ <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+ <key column="PAYMENT_ID"/>
+ ...
+ </joined-subclass>
+</class>]]></programlisting>
+
+ <para>
+ Se requieren cuatro tablas. Las tres tablas de subclase tienen
+ asociaciones de clave primaria a la tabla de superclase (de modo
+ que en el modelo relacional es realmente una asociación uno-a-uno).
+ </para>
+
+ </sect2>
+
+ <sect2 id="inheritance-tablepersubclass-discriminator" revision="2">
+ <title>Tabla por subclase, usando un discriminador</title>
+
+ <para>
+ Observa que la implementación de Hibernate de tabla por subclase
+ no requiere ninguna columna discriminadora. Otros mapeadores
+ objeto/relacional usan una implementación diferente de tabla por
+ subclase que requiere una columna discriminadora de tipo en la tabla
+ de superclase. Este enfoque es mucho más difícil de implementar
+ pero discutiblemente más correcto desde un punto de vista relacional.
+ Si quisieras usar una columna discriminadora con la estrategia de
+ tabla por subclase, puedes combinar el uso de <literal><subclass></literal>
+ y <literal><join></literal>, como sigue:
+ </para>
+
+ <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+ <id name="id" type="long" column="PAYMENT_ID">
+ <generator class="native"/>
+ </id>
+ <discriminator column="PAYMENT_TYPE" type="string"/>
+ <property name="amount" column="AMOUNT"/>
+ ...
+ <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+ <join table="CREDIT_PAYMENT">
+ <key column="PAYMENT_ID"/>
+ <property name="creditCardType" column="CCTYPE"/>
+ ...
+ </join>
+ </subclass>
+ <subclass name="CashPayment" discriminator-value="CASH">
+ <join table="CASH_PAYMENT">
+ <key column="PAYMENT_ID"/>
+ ...
+ </join>
+ </subclass>
+ <subclass name="ChequePayment" discriminator-value="CHEQUE">
+ <join table="CHEQUE_PAYMENT" fetch="select">
+ <key column="PAYMENT_ID"/>
+ ...
+ </join>
+ </subclass>
+</class>]]></programlisting>
+
+ <para>
+ la declaración opcional <literal>fetch="select"</literal> dice a Hibernate
+ que no recupere los datos de la subclase <literal>ChequePayment</literal>
+ usando una unión externa (outer join) al consultar la superclase.
+ </para>
+
+ </sect2>
+
+ <sect2 id="inheritance-mixing-tableperclass-tablepersubclass">
+ <title>Mezclando tabla por jerarquía de clases con tabla por subclase</title>
+
+ <para>
+ Puedes incluso mezclar las estrategias de tabla po jerarquía y tabla por
+ subclase usando este enfoque:
+ </para>
+
+ <programlisting><![CDATA[<class name="Payment" table="PAYMENT">
+ <id name="id" type="long" column="PAYMENT_ID">
+ <generator class="native"/>
+ </id>
+ <discriminator column="PAYMENT_TYPE" type="string"/>
+ <property name="amount" column="AMOUNT"/>
+ ...
+ <subclass name="CreditCardPayment" discriminator-value="CREDIT">
+ <join table="CREDIT_PAYMENT">
+ <property name="creditCardType" column="CCTYPE"/>
+ ...
+ </join>
+ </subclass>
+ <subclass name="CashPayment" discriminator-value="CASH">
+ ...
+ </subclass>
+ <subclass name="ChequePayment" discriminator-value="CHEQUE">
+ ...
+ </subclass>
+</class>]]></programlisting>
+
+ <para>
+ Para cualquiera de estas estrategias de mapeo, una asociación polimórfica
+ a la clase raíz <literal>Payment</literal> es mapeada usando <literal><many-to-one></literal>.
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="payment" column="PAYMENT_ID" class="Payment"/>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="inheritance-tableperconcrete" revision="1">
+ <title>Tabla por clase concreta</title>
+
+ <para>
+ Podríamos ir de dos maneras a la estrategia de mapeo de tabla por clase
+ concreta. La primera es usar <literal><union-subclass></literal>.
+ </para>
+
+ <programlisting><![CDATA[<class name="Payment">
+ <id name="id" type="long" column="PAYMENT_ID">
+ <generator class="sequence"/>
+ </id>
+ <property name="amount" column="AMOUNT"/>
+ ...
+ <union-subclass name="CreditCardPayment" table="CREDIT_PAYMENT">
+ <property name="creditCardType" column="CCTYPE"/>
+ ...
+ </union-subclass>
+ <union-subclass name="CashPayment" table="CASH_PAYMENT">
+ ...
+ </union-subclass>
+ <union-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+ ...
+ </union-subclass>
+</class>]]></programlisting>
+
+ <para>
+ Están implicadas tres tablas. Cada tabla define columnas para todas las
+ propiedades de la clase, inccluyendo las propiedades heredadas.
+ </para>
+
+ <para>
+ La limitación de este enfoque es que si una propiedad es mapeada en la
+ superclase, el nombre de columna debe ser el mismo en todas las tablas
+ de subclase. (Podríamos relajar esto en un lanzamiento futuro de Hibernate.)
+ La estrategia de generador de indentidad no está permitida en la herencia
+ de unión de subclase, de hecho la semilla de clave primaria tiene que ser
+ compartida a través de todas las subclases unidas de una jerarquía.
+ </para>
+
+ </sect2>
+
+ <sect2 id="inheritance-tableperconcreate-polymorphism">
+ <title>Tabla por clase concreta, usando polimorfismo implícito</title>
+
+ <para>
+ Un enfoque alternativo es hacer uso de polimorfismo implícito:
+ </para>
+
+ <programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
+ <id name="id" type="long" column="CREDIT_PAYMENT_ID">
+ <generator class="native"/>
+ </id>
+ <property name="amount" column="CREDIT_AMOUNT"/>
+ ...
+</class>
+
+<class name="CashPayment" table="CASH_PAYMENT">
+ <id name="id" type="long" column="CASH_PAYMENT_ID">
+ <generator class="native"/>
+ </id>
+ <property name="amount" column="CASH_AMOUNT"/>
+ ...
+</class>
+
+<class name="ChequePayment" table="CHEQUE_PAYMENT">
+ <id name="id" type="long" column="CHEQUE_PAYMENT_ID">
+ <generator class="native"/>
+ </id>
+ <property name="amount" column="CHEQUE_AMOUNT"/>
+ ...
+</class>]]></programlisting>
+
+ <para>
+ Nota que en ningún sitio mencionamos la interface <literal>Payment</literal>
+ explícitamente. Nota además que las propiedades de <literal>Payment</literal>
+ son mapeadas en cada una de las subclases. Si quieres evitar duplicación,
+ considera usar entidades XML. (por ejemplo,
+ <literal>[ <!ENTITY allproperties SYSTEM "allproperties.xml"> ]</literal>
+ en la declaración <literal>DOCTYPE</literal> y <literal>&allproperties;</literal>
+ en el mapeo).
+ </para>
+
+ <para>
+ La desventaja de este enfoque es que Hibernate no genera <literal>UNION</literal>s
+ de SQL al realizar consultas polimórficas.
+ </para>
+
+ <para>
+ Para esta estrategia de mapeo, una asociación polimórfica a <literal>Payment</literal>
+ es mapeada generalmente usando <literal><any></literal>.
+ </para>
+
+ <programlisting><![CDATA[<any name="payment" meta-type="string" id-type="long">
+ <meta-value value="CREDIT" class="CreditCardPayment"/>
+ <meta-value value="CASH" class="CashPayment"/>
+ <meta-value value="CHEQUE" class="ChequePayment"/>
+ <column name="PAYMENT_CLASS"/>
+ <column name="PAYMENT_ID"/>
+</any>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="inheritace-mixingpolymorphism">
+ <title>Mezclando polimorfismo implícito con otros mapeos de herencia</title>
+
+ <para>
+ Hay una cosa más por notar acerca de este mapeo. Ya que las subclases se mapean
+ cada una en su propio elemento <literal><class></literal> (y ya que
+ <literal>Payment</literal> es sólo una interface), cada una de las subclases
+ podría ser parte de otra jerarquía de herencia! (Y todavía puedes seguir usando
+ consultas polimórficas contra la interface <literal>Payment</literal>.)
+ </para>
+
+ <programlisting><![CDATA[<class name="CreditCardPayment" table="CREDIT_PAYMENT">
+ <id name="id" type="long" column="CREDIT_PAYMENT_ID">
+ <generator class="native"/>
+ </id>
+ <discriminator column="CREDIT_CARD" type="string"/>
+ <property name="amount" column="CREDIT_AMOUNT"/>
+ ...
+ <subclass name="MasterCardPayment" discriminator-value="MDC"/>
+ <subclass name="VisaPayment" discriminator-value="VISA"/>
+</class>
+
+<class name="NonelectronicTransaction" table="NONELECTRONIC_TXN">
+ <id name="id" type="long" column="TXN_ID">
+ <generator class="native"/>
+ </id>
+ ...
+ <joined-subclass name="CashPayment" table="CASH_PAYMENT">
+ <key column="PAYMENT_ID"/>
+ <property name="amount" column="CASH_AMOUNT"/>
+ ...
+ </joined-subclass>
+ <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">
+ <key column="PAYMENT_ID"/>
+ <property name="amount" column="CHEQUE_AMOUNT"/>
+ ...
+ </joined-subclass>
+</class>]]></programlisting>
+
+ <para>
+ Una vez más, no mencionamos a <literal>Payment</literal> explícitamente.
+ Si ejecutamos una consulta contra la interface <literal>Payment</literal>
+ - por ejemplo, <literal>from Payment</literal> - Hibernate devuelve
+ automáticamente instancias de <literal>CreditCardPayment</literal>
+ (y sus subclases, ya que ellas también implementan <literal>Payment</literal>),
+ <literal>CashPayment</literal> y <literal>ChequePayment</literal> pero
+ no instancias de <literal>NonelectronicTransaction</literal>.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="inheritance-limitations">
+ <title>Limitaciones</title>
+
+ <para>
+ Existen ciertas limitaciones al enfoque de "polimorfismo implícito" en
+ la estrategia de mapeo de tabla por clase concreta. Existen limitaciones
+ algo menos restrictivas a los mapeos <literal><union-subclass></literal>.
+ </para>
+
+ <para>
+ La siguiente tabla muestra las limitaciones de mapeos de tabla por
+ clase concreta, y de polmorfismo implícito, en Hibernate.
+ </para>
+
+ <table frame="topbot">
+ <title>Funcionalidades de mapeo de herencia</title>
+ <tgroup cols='8' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1' colwidth="1*"/>
+ <colspec colname='c2' colwidth="1*"/>
+ <colspec colname='c3' colwidth="1*"/>
+ <colspec colname='c4' colwidth="1*"/>
+ <colspec colname='c5' colwidth="1*"/>
+ <colspec colname='c6' colwidth="1*"/>
+ <colspec colname='c7' colwidth="1*"/>
+ <colspec colname='c8' colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Estrategia de herencia</entry>
+ <entry>muchos-a-uno polimórfica</entry>
+ <entry>uno-a-uno polimórfica</entry>
+ <entry>uno-a-muchos polimórfica</entry>
+ <entry>mushos-a-muchos polimórfica</entry>
+ <entry><literal>load()/get()</literal> polimórficos</entry>
+ <entry>Consultas polimórficas</entry>
+ <entry>Uniones polimórficas</entry>
+ <entry>Recuperación por unión externa (outer join)</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>tabla por jerarquía de clases</entry>
+ <entry><literal><many-to-one></literal></entry>
+ <entry><literal><one-to-one></literal></entry>
+ <entry><literal><one-to-many></literal></entry>
+ <entry><literal><many-to-many></literal></entry>
+ <entry><literal>s.get(Payment.class, id)</literal></entry>
+ <entry><literal>from Payment p</literal></entry>
+ <entry><literal>from Order o join o.payment p</literal></entry>
+ <entry><emphasis>soportada</emphasis></entry>
+ </row>
+ <row>
+ <entry>tabla por subclase</entry>
+ <entry><literal><many-to-one></literal></entry>
+ <entry><literal><one-to-one></literal></entry>
+ <entry><literal><one-to-many></literal></entry>
+ <entry><literal><many-to-many></literal></entry>
+ <entry><literal>s.get(Payment.class, id)</literal></entry>
+ <entry><literal>from Payment p</literal></entry>
+ <entry><literal>from Order o join o.payment p</literal></entry>
+ <entry><emphasis>soportada</emphasis></entry>
+ </row>
+ <row>
+ <entry>tabla por clase concreta (union-subclass)</entry>
+ <entry><literal><many-to-one></literal></entry>
+ <entry><literal><one-to-one></literal></entry>
+ <entry><literal><one-to-many></literal> (para <literal>inverse="true"</literal> solamente)</entry>
+ <entry><literal><many-to-many></literal></entry>
+ <entry><literal>s.get(Payment.class, id)</literal></entry>
+ <entry><literal>from Payment p</literal></entry>
+ <entry><literal>from Order o join o.payment p</literal></entry>
+ <entry><emphasis>soportada</emphasis></entry>
+ </row>
+ <row>
+ <entry>tabla por clase concreta (polimorfismo implícito)</entry>
+ <entry><literal><any></literal></entry>
+ <entry><emphasis>no soportada</emphasis></entry>
+ <entry><emphasis>no soportada</emphasis></entry>
+ <entry><literal><many-to-any></literal></entry>
+ <entry><literal>s.createCriteria(Payment.class).add( Restrictions.idEq(id) ).uniqueResult()</literal></entry>
+ <entry><literal>from Payment p</literal></entry>
+ <entry><emphasis>no suportadas</emphasis></entry>
+ <entry><emphasis>no soportada</emphasis></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </sect1>
+
+</chapter>
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/content/performance.xml (from rev 12794, core/trunk/documentation/manual/es-ES/src/main/docbook/modules/performance.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/performance.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/performance.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,1334 @@
+<chapter id="performance">
+ <title>Mejorando el rendimiento</title>
+
+ <sect1 id="performance-fetching">
+ <title>Estrategias de recuperación</title>
+
+ <para>
+ Una <emphasis>estrategia de recuperación</emphasis> es la estrategia que usará Hibernate para recuperar
+ los objetos asociados cuando la aplicación necesite navegar la asociación. Las estrategias de recuperación
+ pueden ser declaradas en los metadatos de mapeo O/R, o sobrescritas por una consulta HQL o
+ <literal>Criteria</literal> en particular.
+ </para>
+
+ <para>
+ Hibernate3 define las siguientes estrategias de recuperación:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Recuperación por unión (join fetching)</emphasis> - Hibernate recupera la
+ instancia asociada o colección en la misma <literal>SELECT</literal>, usando una
+ <literal>OUTER JOIN</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Recuperación por selección (select fetching)</emphasis> - se usa una segunda
+ <literal>SELECT</literal> para recuperar la entidad asociada o colección. A menos que
+ deshabilites explícitamente la recuperación perezosa especificando <literal>lazy="false"</literal>,
+ la segunda selección sólo será ejecutada cuando realmente accedas a la asociación.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Recuperación por subselección (subselect fetching)</emphasis> - se usa una segunda
+ <literal>SELECT</literal> para recuperar las colecciones asociadas de todas las entidades
+ recuperadas en una consulta o recuperación previa. A menos que deshabilites explícitamente la
+ recuperación perezosa especificando <literal>lazy="false"</literal>, esta segunda selección sólo
+ será ejecutada cuando realmente accedas a la asociación.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Recuperación en lote</emphasis> - una estrategia de optimización para la recuperación
+ por selección - Hibernate recupera un lote de instancias de entidad o colecciones en una sola
+ <literal>SELECT</literal>, especificando una lista de claves primarias o de claves foráneas.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Hibernate también distingue entre:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Recuperación inmediata</emphasis> - una asociación, colección o atributo es recuperado
+ inmediatamente, cuando el dueño es cargado.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Recuperación perezosa de colecciones</emphasis> - se recupera una colección cuando la
+ aplicación invoca una operación sobre la colección. (Esto es por defecto para las colecciones.)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Recuperación por proxy</emphasis> - se recupera una asociación monovaluada cuando se
+ invoca un método que no sea el getter del identificador sobre el objeto asociado.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Recuperación perezosa de atributos</emphasis> - se recupera un atributo o una asociación
+ monovaluada cuando se accede a la variable de instancia (requiere instrumentación del bytecode en
+ tiempo de ejecución). Este enfoque es raramente necesario.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Aquí tenemos dos nociones ortogonales: <emphasis>cuándo</emphasis> se recupera la aplicación,
+ y <emphasis>cómo</emphasis> es recuperada (qué SQL es usado). ¡No las confundas! Usamos
+ <literal>fetch</literal> para afinar el rendimiento. Podemos usar <literal>lazy</literal> para
+ definir un contrato sobre qué datos están siempre disponibles en cualquier instancia separada de
+ una clase en particular.
+ </para>
+
+ <sect2 id="performance-fetching-lazy">
+ <title>Trabajando con asociaciones perezosas</title>
+
+ <para>
+ Por defecto, Hibernate3 usa una recuperación perezosa por selección para colecciones
+ y una recuperación por proxy perezosa para asociaciones monovaluadas. Estas políticas por
+ defecto tienen sentido para casi todas las asociaciones en casi todas las aplicaciones.
+ </para>
+
+ <para>
+ <emphasis>Nota:</emphasis> si estableces <literal>hibernate.default_batch_fetch_size</literal>, Hibernate
+ usará la optimización de recuperación en lotes para recuperación perezosa (esta optimización también puede
+ ser habilitada a un nivel más granularizado).
+ </para>
+
+ <para>
+ Sin embargo, la recuperación perezosa plantea un problema del que tienes que estar al tanto. Acceder
+ a una asociación perezosa fuera del contexto de una sesión de Hibernate abierta resultará en una
+ excepción. Por ejemplo:
+ </para>
+
+ <programlisting><![CDATA[s = sessions.openSession();
+Transaction tx = s.beginTransaction();
+
+User u = (User) s.createQuery("from User u where u.name=:userName")
+ .setString("userName", userName).uniqueResult();
+Map permissions = u.getPermissions();
+
+tx.commit();
+s.close();
+
+Integer accessLevel = (Integer) permissions.get("accounts"); // Error!]]></programlisting>
+
+ <para>
+ Ya que la colección de permisos no fue inicializada cuando se cerró la <literal>Session</literal>,
+ la colección no será capaz de cargar su estado. <emphasis>Hibernate no soporta la inicialización
+ perezosa de objetos separados</emphasis>. La solución es mover el código que lee de la colección
+ a justo antes que la transacción sea comprometida.
+ </para>
+
+ <para>
+ Alternativamente, podríamos usar una colección no perezosa o asociación, especificando
+ <literal>lazy="false"</literal> para el mapeo de asociación. Sin embargo, está pensado
+ que la inicialización perezosa sea usada para casi todas las colecciones y asociaciones.
+ ¡Si defines demasiadas asociaciones no perezosas en tu modelo de objetos, Hibernate terminará
+ necesitando recuperar la base de datos entera en cada transacción!
+ </para>
+
+ <para>
+ Por otro lado, frecuentemente necesitamos elegir la recuperación por unión (que es no perezosa
+ por naturaleza) en vez de la recuperación por selección en una transacción en particular. Veremos
+ ahora cómo personalizar la estrategia de recuperación. En Hibernate3, los mecanismos para elegir una
+ estrategia de recuperación son idénticas a las de las asociaciones monovaluadas y colecciones.
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-fetching-custom" revision="3">
+ <title>Afinando las estrategias de recuperación</title>
+
+ <para>
+ La recuperación por selección (la preestablecida) es extremadamente vulnerable a problemas de
+ selección N+1, de modo querríamos habilitar la recuperación por unión (join fetching) en el
+ documento de mapeo:
+ </para>
+
+ <programlisting><![CDATA[<set name="permissions"
+ fetch="join">
+ <key column="userId"/>
+ <one-to-many class="Permission"/>
+</set]]></programlisting>
+
+ <programlisting><![CDATA[<many-to-one name="mother" class="Cat" fetch="join"/>]]></programlisting>
+
+ <para>
+ La estrategia de recuperación definida en el documento de mapeo afecta a:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ las recuperaciones vía <literal>get()</literal> o <literal>load()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ las recuperaciones que ocurren implícitamente cuando se navega una asociación
+ (recuperación perezosa)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ las consultas de <literal>Criteria</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Usualmente, no usamos el documento de mapeo para personalizar la recuperación. En cambio, mantenemos el
+ comportamiento por defecto, y lo sobrescribimos para una transacción en particular, usando
+ <literal>left join fetch</literal> en HQL. Esto le dice a Hibernate que recupere la asociación
+ tempranamente en la primera selección, usando una unión externa. En la API de consulta de
+ <literal>Criteria</literal>, usarías <literal>setFetchMode(FetchMode.JOIN)</literal>.
+ </para>
+
+ <para>
+ Si acaso lo deseases, podrías cambiar la estrategia de recuperación usada por
+ <literal>get()</literal> or <literal>load()</literal>; simplemente usa una consulta
+ <literal>Criteria</literal>, por ejemplo:
+ </para>
+
+ <programlisting><![CDATA[User user = (User) session.createCriteria(User.class)
+ .setFetchMode("permissions", FetchMode.JOIN)
+ .add( Restrictions.idEq(userId) )
+ .uniqueResult();]]></programlisting>
+
+ <para>
+ (Esto es el equivalente de Hibernate de lo que otras soluciones ORM llaman un "plan de recuperación".)
+ </para>
+
+ <para>
+ Una forma completamente diferente de evitar problemas con selecciones N+1 es usar el caché de
+ segundo nivel.
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-fetching-proxies" revision="2">
+ <title>Proxies de asociaciones de un solo extremo</title>
+
+ <para>
+ La recuperación perezosa de colecciones está implementada usando la implementación de colecciones
+ persistentes propia de Hibernate. Sin embargo, se necesita un mecanismo diferente para un comportamiento
+ perezoso en las asociaciones de un solo extremo. La entidad objetivo de la asociación debe ser tratada
+ con proxies. Hibernate implementa proxies de inicialización perezosa para objetos persistentes usando
+ mejora del bytecode en tiempo de ejecución (por medio de la excelente biblioteca CGLIB).
+ </para>
+
+ <para>
+ Por defecto, Hibernate3 genera proxies (en el arranque) para todas las clases persistentes y los usa
+ para habilitar la recuperación perezosa de asociaciones <literal>muchos-a-uno</literal> y
+ <literal>uno-a-uno</literal>.
+ </para>
+
+ <para>
+ El fichero de mapeo puede declarar una interface a usar como interface de proxy para esa clase,
+ con el atributo <literal>proxy</literal>. Por defecto, Hibernate usa una subclase de la clase.
+ <emphasis>Nota que la clase tratada con proxies debe implementar un constructor por defecto con al
+ menos visibilidad de paquete. ¡Recomendamos este constructor para todas las clases persistentes!</emphasis>
+ </para>
+
+ <para>
+ Hay algunos puntos a tener en cuenta al extender este enfoque a clases polimórficas, por ejemplo.
+ </para>
+
+ <programlisting><![CDATA[<class name="Cat" proxy="Cat">
+ ......
+ <subclass name="DomesticCat">
+ .....
+ </subclass>
+</class>]]></programlisting>
+
+ <para>
+ Primero, las instancias de <literal>Cat</literal> nunca serán objeto de un cast a
+ <literal>DomesticCat</literal>, incluso aunque la instancia subyacente sea instancia de
+ <literal>DomesticCat</literal>:
+ </para>
+
+ <programlisting><![CDATA[Cat cat = (Cat) session.load(Cat.class, id); // instantiate a proxy (does not hit the db)
+if ( cat.isDomesticCat() ) { // hit the db to initialize the proxy
+ DomesticCat dc = (DomesticCat) cat; // Error!
+ ....
+}]]></programlisting>
+
+ <para>
+ Segundo, es posible romper con el operador <literal>==</literal> de un proxy.
+ </para>
+
+ <programlisting><![CDATA[Cat cat = (Cat) session.load(Cat.class, id); // instantiate a Cat proxy
+DomesticCat dc =
+ (DomesticCat) session.load(DomesticCat.class, id); // acquire new DomesticCat proxy!
+System.out.println(cat==dc); // false]]></programlisting>
+
+ <para>
+ Sin embargo, la situación no en absoluta tan mala como parece. Aunque tenemos ahora dos referencias
+ a objetos proxy diferentes, la instancia subyacente será aún el mismo objeto:
+ </para>
+
+ <programlisting><![CDATA[cat.setWeight(11.0); // hit the db to initialize the proxy
+System.out.println( dc.getWeight() ); // 11.0]]></programlisting>
+
+ <para>
+ Tercero, no debes usar un proxy CGLIB para una clase <literal>final</literal> o una clase
+ con algún método <literal>final</literal>.
+ </para>
+
+ <para>
+ Finalmente, si tu objeto persistente adquiere cualquier recurso bajo instanciación
+ (por ejemplo, en inicializadores o constructores por defecto), entonces esos recursos
+ serán adquiridos también por el proxy. La clase del proxy es una subclase real de la clase
+ persistente.
+ </para>
+
+ <para>
+ Estos problemas se deben a limitaciones fundamentales en el modelo de herencia única de Java.
+ Si deseas evitar estos problemas cada una de tus clases persistentes deben implementar una
+ interface que declare sus métodos de negocio. Debes especificar estas interfaces en el fichero
+ de mapeo. Por ejemplo:
+ </para>
+
+ <programlisting><![CDATA[<class name="CatImpl" proxy="Cat">
+ ......
+ <subclass name="DomesticCatImpl" proxy="DomesticCat">
+ .....
+ </subclass>
+</class>]]></programlisting>
+
+ <para>
+ donde <literal>CatImpl</literal> implementa la interface <literal>Cat</literal> y
+ <literal>DomesticCatImpl</literal> implementa la interface <literal>DomesticCat</literal>.
+ Entonces <literal>load()</literal> o <literal>iterate()</literal> pueden devolver instancias de
+ <literal>Cat</literal> y <literal>DomesticCat</literal>. (Nota que <literal>list()</literal>
+ usualmente no devuelve proxies.)
+ </para>
+
+ <programlisting><![CDATA[Cat cat = (Cat) session.load(CatImpl.class, catid);
+Iterator iter = session.createQuery("from CatImpl as cat where cat.name='fritz'").iterate();
+Cat fritz = (Cat) iter.next();]]></programlisting>
+
+ <para>
+ Las relaciones también son inicializadas perezosamente. Esto significa que debes declarar
+ cualquier propiedad como de tipo <literal>Cat</literal>, no <literal>CatImpl</literal>.
+ </para>
+
+ <para>
+ Ciertas operaciones <emphasis>no</emphasis> requieren inicialización de proxies.
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>equals()</literal>, si la clase persistente no sobrescribe <literal>equals()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>hashCode()</literal>, si la clase persistente no sobrescribe
+ <literal>hashCode()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ El método getter del identificador
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Hibernate detectará las clase persistentes que sobrescriban <literal>equals()</literal> o
+ <literal>hashCode()</literal>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-fetching-initialization">
+ <title>Inicializando colecciones y proxies</title>
+
+ <para>
+ Una <literal>LazyInitializationException</literal> será lanzada por Hibernate si una colección
+ o proxy sin inicializar es accedido fuera del ámbito de la <literal>Session</literal>, es decir,
+ cuando la entidad que posee la colección o que tiene la referencia al proxy esté en el estado
+ separada.
+ </para>
+
+ <para>
+ A veces necesitamos asegurarnos que un proxy o colección esté inicializado antes de cerrar la
+ <literal>Session</literal>. Por supuesto, siempre podemos forzar la inicialización llamando a
+ <literal>cat.getSex()</literal> o <literal>cat.getKittens().size()</literal>, por ejemplo.
+ Pero esto es confuso a lectores del código y no es conveniente para código genérico.
+ </para>
+
+ <para>
+ Los métodos estáticos <literal>Hibernate.initialize()</literal> y
+ <literal>Hibernate.isInitialized()</literal> proveen a la aplicación de una forma conveniente de
+ trabajar con colecciones o proxies inicializados perezosamente.
+ <literal>Hibernate.initialize(cat)</literal> forzará la inicialización de un proxy,
+ <literal>cat</literal>, en tanto su <literal>Session</literal> esté todavía abierta.
+ <literal>Hibernate.initialize( cat.getKittens() )</literal> tiene un efecto similar para la colección
+ de gatitos.
+ </para>
+
+ <para>
+ Otra opción es mantener la <literal>Session</literal> abierta hasta que todas las colecciones
+ y proxies necesarios hayan sido cargados. En algunas arquitecturas de aplicación, particularmente
+ en aquellas donde el código que accede a los datos usando Hibernate, y el código que los usa están
+ en capas de aplicación diferentes o procesos físicos diferentes, puede ser un problema asegurar que
+ la <literal>Session</literal> esté abierta cuando se inicializa una colección. Existen dos formas
+ básicas de tratar este tema:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ En una aplicación basada web, puede usarse un filtro de servlets para cerrar la
+ <literal>Session</literal> sólo bien al final de una petición de usuario, una
+ vez que el rendering de la vista esté completa (el patrón <emphasis>Sesión Abierta en
+ Vista (Open Session in View)</emphasis>). Por supuesto, estos sitios requieren una
+ fuerte demanda de corrección del manejo de excepciones de tu infraestructura de
+ aplicación. Es de una importancia vital que la <literal>Session</literal> esté
+ cerrada y la transacción terminada antes de volver al usuario, incluso cuando ocurra
+ una excepción durante el rendering de la página. Para este enfoque, el filtro de servlet tiene
+ que ser capaz de accceder la <literal>Session</literal>. Recomendamos que se use una variable
+ <literal>ThreadLocal</literal> para tener la <literal>Session</literal> actual (ver
+ el capítulo 1, <xref linkend="quickstart-playingwithcats"/>, para una implementación de ejemplo).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ En una aplciación con una grada de negocios separada, la lógica de negocio debe "preparar"
+ todas las colecciones que se vayan a necesitar por la grada web antes de volver.
+ Esto significa que la grada de negocios debe cargar todos los datos y devolver a la grada de
+ presentación web todos los datos que se requieran para un caso de uso en particular
+ ya inicializados. Usualmente, la aplicación llama a <literal>Hibernate.initialize()</literal>
+ para cada colección que se necesitará en la grada web (esta llamada debe ocurrir antes que la
+ sesión sea cerrada) o recupera la colección tempranamente usando una consulta de Hibernate con una
+ cláusula <literal>FETCH</literal> o una <literal>FetchMode.JOIN</literal> en
+ <literal>Criteria</literal>. Esto es usualmente más fácil si adoptas el patrón
+ <emphasis>Comando</emphasis> en vez de un <emphasis>Fachada de Sesión</emphasis>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Puedes también adjuntar un objeto cargado previamente a una nueva <literal>Session</literal>
+ con <literal>merge()</literal> o <literal>lock()</literal> antes de acceder a colecciones
+ no inicializadas (u otros proxies). ¡No, Hibernate no, y ciertamente <emphasis>no
+ debe</emphasis> hacer esto automáticamente, ya que introduciría semánticas de transacción ad hoc!
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ A veces no quieres inicializar una colección grande, pero necesitas aún alguna informacion sobre
+ ella (como su tamaño) o un subconjunto de los datos.
+ </para>
+
+ <para>
+ Puedes usar un filtro de colecciones para obtener el tamaño de una colección sin inicializarla:
+ </para>
+
+ <programlisting><![CDATA[( (Integer) s.createFilter( collection, "select count(*)" ).list().get(0) ).intValue()]]></programlisting>
+
+ <para>
+ El método <literal>createFilter()</literal> se usa también para recuperar eficientemente subconjuntos
+ de una colección sin necesidad de inicializar toda la colección:
+ </para>
+
+ <programlisting><![CDATA[s.createFilter( lazyCollection, "").setFirstResult(0).setMaxResults(10).list();]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="performance-fetching-batch">
+ <title>Usando recuperación en lotes</title>
+
+ <para>
+ Hibernate puede hacer un uso eficiente de la recuperación en lotes, esto es, Hibernate puede cargar
+ muchos proxies sin inicializar si se accede a un proxy (o colecciones). La recuperación en lotes es una
+ optimización de la estrategia de recuperación por selección perezosa. Hay dos formas en que puedes afinar
+ la recuperación en lotes: a nivel de la clase o de la colección.
+ </para>
+
+ <para>
+ La recuperación en lotes para clases/entidades es más fácil de entender. Imagina que tienes la siguiente
+ situación en tiempo de ejecución: Tienes 25 instancias de <literal>Cat</literal> cargadas en una
+ <literal>Session</literal>, cada <literal>Cat</literal> tiene una referencia a su <literal>owner</literal>,
+ una <literal>Person</literal>. La clase <literal>Person</literal> está mapeada con un proxy,
+ <literal>lazy="true"</literal>. Si ahora iteras a través de todos los gatos y llamas a
+ <literal>getOwner()</literal> para cada uno, Hibernate por defecto ejecutará 25 sentencias
+ <literal>SELECT</literal> para traer los dueños tratados con proxies. Puedes afinar este comportamiento
+ especificando un <literal>batch-size</literal> en el mapeo de <literal>Person</literal>:
+ </para>
+
+ <programlisting><![CDATA[<class name="Person" batch-size="10">...</class>]]></programlisting>
+
+ <para>
+ Hibernate ahora ejecutará sólo tres consultas, el patrón es 10, 10, 5.
+ </para>
+
+ <para>
+ También puedes habilitar la recuperación en lotes para colecciones. Por ejemplo, si cada
+ <literal>Person</literal> tiene una colección perezosa de <literal>Cat</literal>s, y hay 10
+ personas actualmente cargadas en la <literal>Session</literal>, iterar a través de las 10 personas
+ generará 10 <literal>SELECT</literal>s, una para cada llamada a <literal>getCats()</literal>.
+ Si habilitas la recuperación en lotes para la colección de <literal>cats</literal> en el mapeo de
+ <literal>Person</literal>, Hibernate puede recuperar por adelantado las colecciones:
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <set name="cats" batch-size="3">
+ ...
+ </set>
+</class>]]></programlisting>
+
+ <para>
+ Con un <literal>batch-size</literal> de 3, Hibernate cargará 3, 3, 3, 1 colecciones en cuatro
+ <literal>SELECT</literal>s. Una vez más, el valor del atributo depende del número esperado de
+ colecciones sin inicializar en una <literal>Session</literal> en particular.
+ </para>
+
+ <para>
+ La recuperación de coleccione en lotes es particularmente útil si tienes un árbol anidado de
+ ítems, es decir, el típico patrón de cuenta de materiales. (Aunque un <emphasis>conjunto
+ anidado</emphasis> o una <emphasis>ruta materializada</emphasis> podría ser una mejor opción
+ para árboles que sean de lectura en la mayoría de los casos.)
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-fetching-subselect">
+ <title>Usando recuperación por subselección</title>
+
+ <para>
+ Si una colección perezosa o proxy monovaluado tiene que ser recuperado, Hibernate los carga a todos,
+ volviendo a ejecutar la consulta original en una subselección. Esto funciona de la misma forma que
+ la recuperación en lotes, sin carga fragmentaria.
+ </para>
+
+ <!-- TODO: Write more about this -->
+
+ </sect2>
+
+ <sect2 id="performance-fetching-lazyproperties">
+ <title>Usando recuperación perezosa de propiedades</title>
+
+ <para>
+ Hibernate3 soporta la recuperación perezosa de propiedades individuales. Esta técnica de optimización
+ es también conocida como <emphasis>grupos de recuperación (fetch groups)</emphasis>. Por favor, nota
+ que éste es mayormente un aspecto de marketing, ya que en la práctica, optimizar lecturas de filas es
+ mucho más importante que la optimización de lectura de columnas. Sin embargo, cargar sólo algunas
+ propiedades de una clase podría ser útil en casos extremos, cuando tablas heredadas tienen cientos de
+ columnas y el modelo de datos no puede ser mejorado.
+ </para>
+
+ <para>
+ Para habilitar la carga perezosa de propiedades, establece el atributo <literal>lazy</literal> en tus
+ mapeos de propiedades:
+ </para>
+
+ <programlisting><![CDATA[<class name="Document">
+ <id name="id">
+ <generator class="native"/>
+ </id>
+ <property name="name" not-null="true" length="50"/>
+ <property name="summary" not-null="true" length="200" lazy="true"/>
+ <property name="text" not-null="true" length="2000" lazy="true"/>
+</class>]]></programlisting>
+
+ <para>
+ ¡La carga perezosa de propiedades requiere la instrumentación del bytecode en tiempo
+ de construcción! Si tus clases persistentes no son mejoradas, Hibernate ignorará silenciosamente
+ la configuración perezosa de propiedades y caerá en recuperación inmediata.
+ </para>
+
+ <para>
+ Para la instrumentación del bytecode, usa la siguiente tarea Ant:
+ </para>
+
+ <programlisting><![CDATA[<target name="instrument" depends="compile">
+ <taskdef name="instrument" classname="org.hibernate.tool.instrument.InstrumentTask">
+ <classpath path="${jar.path}"/>
+ <classpath path="${classes.dir}"/>
+ <classpath refid="lib.class.path"/>
+ </taskdef>
+
+ <instrument verbose="true">
+ <fileset dir="${testclasses.dir}/org/hibernate/auction/model">
+ <include name="*.class"/>
+ </fileset>
+ </instrument>
+</target>]]></programlisting>
+
+ <para>
+ Una forma diferente (¿mejor?) de evitar lecturas innecesarias de columnas, al menos para
+ transacciones de sólo lectura es usar las funcionalidades de proyección de consultas HQL o Criteria.
+ Esto evita la necesidad de procesar el bytecode en tiempo de construcción y ciertamente es una solución
+ preferida.
+ </para>
+
+ <para>
+ Puedes forzar la usual recuperación temprana de propiedades usando <literal>fetch all properties</literal>
+ en HQL.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="performance-cache" revision="1">
+ <title>El Caché de Segundo Nivel</title>
+
+ <para>
+ Una <literal>Session</literal> de Hibernate es una caché de datos persistentes a nivel de transacción.
+ Es posible configurar un cluster o caché a nivel de JVM (a nivel de <literal>SessionFactory</literal>)
+ sobre una base de clase-a-clase o colección-a-colección. Puedes incluso enchufar una caché en cluster.
+ Sé cuidadoso. Las cachés nunca están al tanto de los cambios hechos por otra aplicación al almacén persistente
+ (aunque pueden ser configurados para expirar regularmente los datos en caché).
+ </para>
+
+ <para>
+ Por defecto, Hibernate usa EHCache para caching a nivel de JVM. (El soporte a JCS ahora está despreciado
+ y será quitado en una futura versión de Hibernate.) Puedes elegir una implementación diferente estableciendo
+ el nombre de una clase que implemente <literal>org.hibernate.cache.CacheProvider</literal> usando la propiedad
+ <literal>hibernate.cache.provider_class</literal>.
+ </para>
+
+ <table frame="topbot" id="cacheproviders" revision="1">
+ <title>Proveedores de Caché</title>
+ <tgroup cols='5' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1' colwidth="1*"/>
+ <colspec colname='c2' colwidth="3*"/>
+ <colspec colname='c3' colwidth="1*"/>
+ <colspec colname='c4' colwidth="1*"/>
+ <colspec colname='c5' colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Caché</entry>
+ <entry>clase del Provedor</entry>
+ <entry>Tipo</entry>
+ <entry>Cluster Seguro</entry>
+ <entry>Caché de Consultas Soportado</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>Hashtable (no pensado para uso en producción)</entry>
+ <entry><literal>org.hibernate.cache.HashtableCacheProvider</literal></entry>
+ <entry>memoria</entry>
+ <entry></entry>
+ <entry>sí</entry>
+ </row>
+ <row>
+ <entry>EHCache</entry>
+ <entry><literal>org.hibernate.cache.EhCacheProvider</literal></entry>
+ <entry>memoria, disco</entry>
+ <entry></entry>
+ <entry>sí</entry>
+ </row>
+ <row>
+ <entry>OSCache</entry>
+ <entry><literal>org.hibernate.cache.OSCacheProvider</literal></entry>
+ <entry>memoria, disco</entry>
+ <entry></entry>
+ <entry>sí</entry>
+ </row>
+ <row>
+ <entry>SwarmCache</entry>
+ <entry><literal>org.hibernate.cache.SwarmCacheProvider</literal></entry>
+ <entry>clusterizado (ip multicast)</entry>
+ <entry>sí (invalidación en cluster)</entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry>TreeCache de JBoss</entry>
+ <entry><literal>org.hibernate.cache.TreeCacheProvider</literal></entry>
+ <entry>clusterizado (ip multicast), transaccional</entry>
+ <entry>sí (replicación)</entry>
+ <entry>sí (requiere sincronización de reloj)</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <sect2 id="performance-cache-mapping">
+ <title>Mapeos de caché</title>
+
+ <para>
+ El elemento <literal><cache></literal> de una mapeo de clase o colección tiene la siguiente
+ forma:
+ </para>
+
+ <programlistingco>
+ <areaspec>
+ <area id="cache1" coords="2 70"/>
+ </areaspec>
+ <programlisting><![CDATA[<cache
+ usage="transactional|read-write|nonstrict-read-write|read-only"
+/>]]></programlisting>
+ <calloutlist>
+ <callout arearefs="cache1">
+ <para>
+ <literal>usage</literal> especifica la estrategia de caching:
+ <literal>transactional</literal>,
+ <literal>read-write</literal>,
+ <literal>nonstrict-read-write</literal> o
+ <literal>read-only</literal>
+ </para>
+ </callout>
+ </calloutlist>
+ </programlistingco>
+
+ <para>
+ Alternativamente (¿preferiblemente?), puedes especificar los elementos
+ <literal><class-cache></literal> y <literal><collection-cache></literal> en
+ <literal>hibernate.cfg.xml</literal>.
+ </para>
+
+ <para>
+ El atributo <literal>usage</literal> especifica una <emphasis>estrategia de concurrencia al
+ caché</emphasis>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-cache-readonly">
+ <title>Estrategia: sólo lectura (read only)</title>
+
+ <para>
+ Si tu aplicación necesita leer pero nunca modificar las instancias de una clase persistente,
+ puede usarse un caché <literal>read-only</literal>. Esta es la mejor y más simple estrategia.
+ Es incluso perfectamente segura de usar en un cluster.
+ </para>
+
+ <programlisting><![CDATA[<class name="eg.Immutable" mutable="false">
+ <cache usage="read-only"/>
+ ....
+</class>]]></programlisting>
+
+ </sect2>
+
+
+ <sect2 id="performance-cache-readwrite">
+ <title>Estrategia: lectura/escritura (read/write)</title>
+
+ <para>
+ Si la aplicación necesita actualizar datos, un caché <literal>read-write</literal> podría ser apropiado.
+ Esta estrategia de caché nunca debe ser usada si se requiere nivel de aislamiento serializable de
+ transacciones. Si el caché es usado en un entorno JTA, debes especificar la propiedad
+ <literal>hibernate.transaction.manager_lookup_class</literal>, mencionando una estrategia para obtener
+ el <literal>TransactionManager</literal> de JTA. En otros entornos, debes asegurarte que la transacción
+ esté completada cuando se llame a <literal>Session.close()</literal> o
+ <literal>Session.disconnect()</literal>. Si deseas usar esta estrategia en un cluster, debes asegurarte
+ que la implementación de caché subyacente soporta bloqueos. Los provedores de caché internos
+ predeterminados <emphasis>no</emphasis> no lo soportan.
+ </para>
+
+ <programlisting><![CDATA[<class name="eg.Cat" .... >
+ <cache usage="read-write"/>
+ ....
+ <set name="kittens" ... >
+ <cache usage="read-write"/>
+ ....
+ </set>
+</class>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="performance-cache-nonstrict">
+ <title>Estrategia: lectura/escritura no estricta (nonstrict read/write)</title>
+
+ <para>
+ Si la aplicación necesita sólo ocasionalmente actualizar datos (es decir, es extremadamente inprobable
+ que dos transacciones intenten actualizar el mismo ítem simultáneamente) y no se requiere de un
+ aislamiento de transacciones estricto, un caché <literal>nonstrict-read-write</literal> podría ser
+ apropiado. Si se usa el caché en un entorno JTA, debes especificar
+ <literal>hibernate.transaction.manager_lookup_class</literal>. En otros entornos, debes asegurarte que la
+ transacción se haya completado cuando se llame a <literal>Session.close()</literal> o
+ <literal>Session.disconnect()</literal>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-cache-transactional">
+ <title>Estrategia: transaccional</title>
+
+ <para>
+ La estrategia de caché <literal>transactional</literal> brinda soporte a provedores de cachés
+ completamente transaccionales como TreeCache de JBoss. Un caché así, puede sólo ser usado en un
+ entorno JTA y debes especificar <literal>hibernate.transaction.manager_lookup_class</literal>.
+ </para>
+
+ </sect2>
+
+ <para>
+ Ninguno de los provedores de caché soporta todas las estrategias de concurrencia al caché. La siguiente
+ tabla muestra qué provedores son compatibles con qué estrategias de concurrencia.
+ </para>
+
+ <table frame="topbot">
+ <title>Soporte a Estrategia de Concurrencia a Caché</title>
+ <tgroup cols='5' align='left' colsep='1' rowsep='1'>
+ <colspec colname='c1' colwidth="1*"/>
+ <colspec colname='c2' colwidth="1*"/>
+ <colspec colname='c3' colwidth="1*"/>
+ <colspec colname='c4' colwidth="1*"/>
+ <colspec colname='c5' colwidth="1*"/>
+ <thead>
+ <row>
+ <entry>Caché</entry>
+ <entry>read-only</entry>
+ <entry>nonstrict-read-write</entry>
+ <entry>read-write</entry>
+ <entry>transactional</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>Hashtable (no pensado para uso en producción)</entry>
+ <entry>sí</entry>
+ <entry>sí</entry>
+ <entry>sí</entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry>EHCache</entry>
+ <entry>sí</entry>
+ <entry>sí</entry>
+ <entry>sí</entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry>OSCache</entry>
+ <entry>sí</entry>
+ <entry>sí</entry>
+ <entry>sí</entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry>SwarmCache</entry>
+ <entry>sí</entry>
+ <entry>sí</entry>
+ <entry></entry>
+ <entry></entry>
+ </row>
+ <row>
+ <entry>JBoss TreeCache</entry>
+ <entry>sí</entry>
+ <entry></entry>
+ <entry></entry>
+ <entry>sí</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </sect1>
+
+ <sect1 id="performance-sessioncache" revision="2">
+ <title>Gestionando los cachés</title>
+
+ <para>
+ Siempre que pases un objeto a <literal>save()</literal>, <literal>update()</literal>
+ o <literal>saveOrUpdate()</literal> y siempre que recuperes un objeto usando
+ <literal>load()</literal>, <literal>get()</literal>, <literal>list()</literal>,
+ <literal>iterate()</literal> o <literal>scroll()</literal>, ese objeto es agregado
+ al caché interno de la <literal>Session</literal>.
+ </para>
+ <para>
+ Cuando subsecuentemente se llame a <literal>flush()</literal>, el estado de ese objeto será
+ sincronizado con la base de datos. Si no quieres que ocurra esta sincronización o si estás
+ procesando un número enorme de objetos y necesitas gestionar la memoria eficientemente,
+ puede usarse el método <literal>evict()</literal> para quitar el objeto y sus colecciones
+ del caché de primer nivel.
+ </para>
+
+ <programlisting><![CDATA[ScrollableResult cats = sess.createQuery("from Cat as cat").scroll(); //a huge result set
+while ( cats.next() ) {
+ Cat cat = (Cat) cats.get(0);
+ doSomethingWithACat(cat);
+ sess.evict(cat);
+}]]></programlisting>
+
+ <para>
+ La <literal>Session</literal> también provee un método <literal>contains()</literal> para determinar
+ si una instancia pertenece al caché de la sesión.
+ </para>
+
+ <para>
+ Para desahuciar (evict) todos los objetos del caché de sesión, llama a <literal>Session.clear()</literal>.
+ </para>
+
+ <para>
+ Para el caché de segundo nivel, hay métodos definidos en <literal>SessionFactory</literal> para
+ desahuciar el estado en caché de una instancia, clase entera, instancia de colección o rol
+ enter de colección.
+ </para>
+
+ <programlisting><![CDATA[sessionFactory.evict(Cat.class, catId); //evict a particular Cat
+sessionFactory.evict(Cat.class); //evict all Cats
+sessionFactory.evictCollection("Cat.kittens", catId); //evict a particular collection of kittens
+sessionFactory.evictCollection("Cat.kittens"); //evict all kitten collections]]></programlisting>
+
+ <para>
+ El <literal>CacheMode</literal> controla cómo una sesión en particular interactúa con el caché de segundo
+ nivel.
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <literal>CacheMode.NORMAL</literal> - lee ítems desde y escribe ítems hacia el caché de segundo nivel
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>CacheMode.GET</literal> - lee ítems del caché de segundo nivel, pero no escribe al caché de
+ segundo nivel excepto al actualizar datos
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>CacheMode.PUT</literal> - escribe ítems al caché de segundo nivel, pero no lee del caché de segundo
+ nivel
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>CacheMode.REFRESH</literal> - escribe ítems al caché de segundo nivel, pero no lee del caché de
+ segundo nivel, saltándose el efecto de <literal>hibernate.cache.use_minimal_puts</literal>, forzando
+ un refresco del caché de segundo nivel para todos los ítems leídos de la base de datos
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Para navegar por los contenidos de una región de caché de segundo nivel o de consultas, usa la API de
+ <literal>Statistics</literal>:
+ </para>
+
+ <programlisting><![CDATA[Map cacheEntries = sessionFactory.getStatistics()
+ .getSecondLevelCacheStatistics(regionName)
+ .getEntries();]]></programlisting>
+
+ <para>
+ Necesitarás habilitar las estadísticas y, opcionalmente, forzar a Hibernate para que guarde las
+ entradas del caché en un formato más entendible por humanos:
+ </para>
+
+ <programlisting><![CDATA[hibernate.generate_statistics true
+hibernate.cache.use_structured_entries true]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="performance-querycache" revision="1">
+ <title>El Caché de Consultas</title>
+
+ <para>
+ Los conjuntos resultado de consultas también pueden tratarse en caché. Esto sólo es útil para
+ consultas que se ejecutan frecuentemente con los mismos parámetros. Para usar el caché de consultas
+ primero debes habilitarlo:
+ </para>
+
+ <programlisting><![CDATA[hibernate.cache.use_query_cache true]]></programlisting>
+
+ <para>
+ Esta configuración causa la creación de dos nuevas regiones de caché - una teniendo en caché
+ conjuntos resultado de consulta (<literal>org.hibernate.cache.StandardQueryCache</literal>),
+ el otro teniendo timestamps de las actualizaciones más recientes a tablas consultables
+ (<literal>org.hibernate.cache.UpdateTimestampsCache</literal>). Nota que el caché de consultas
+ no pone en caché el estado de las entidades reales en el conjunto resultado; sólo tiene en caché
+ valores indentificadores y resultados de tipo de valor. De modo que el caché de consultas siempre
+ debe ser usado en conjunción con el caché de segundo nivel.
+ </para>
+
+ <para>
+ La mayoría de consultas no se benefician del tratamiento en caché, de modo que por defecto las
+ consultas no son tratadas en caché. Para habilitar el tratamiento en caché, llama a
+ <literal>Query.setCacheable(true)</literal>. Esta llamada permite a la consulta buscar
+ resultados existentes en caché o agregar sus resultados al caché cuando se ejecuta.
+ </para>
+
+ <para>
+ Si requieres un control finamente granularizado sobre las políticas de expiración del caché de
+ consultas, puedes especificar una región de caché con nombre para una consulta en particular
+ llamando a <literal>Query.setCacheRegion()</literal>.
+ </para>
+
+ <programlisting><![CDATA[List blogs = sess.createQuery("from Blog blog where blog.blogger = :blogger")
+ .setEntity("blogger", blogger)
+ .setMaxResults(15)
+ .setCacheable(true)
+ .setCacheRegion("frontpages")
+ .list();]]></programlisting>
+
+ <para>
+ Si la consulta debe forzar un refresco de si región del caché de consultas, debes llamar a
+ <literal>Query.setCacheMode(CacheMode.REFRESH)</literal>. Esto es particularmente útil en casos donde
+ los datos subyacentes pueden haber sido actualizados por medio de un proceso separado (es decir,
+ no modificados a través de Hibernate) y permite a la aplicación refrescar selectivamente conjuntos
+ resultado de consultas en particular. Esto es una alternativa más eficient al desahuciamiento de una
+ región del caché de consultas vía <literal>SessionFactory.evictQueries()</literal>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="performance-collections">
+ <title>Entendiendo el rendimiento de Colecciones</title>
+
+ <para>
+ Ya hemos llevado un buen tiempo hablando sobre colecciones.
+ En esta sección resaltaremos un par de temas más sobre cómo las colecciones
+ se comportan en tiempo de ejecución.
+ </para>
+
+ <sect2 id="performance-collections-taxonomy">
+ <title>Taxonomia</title>
+
+ <para>Hibernate define tres tipos básicos de colecciones:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>colecciones de valores</para>
+ </listitem>
+ <listitem>
+ <para>asociaciones uno a muchos</para>
+ </listitem>
+ <listitem>
+ <para>asociaciones muchos a muchos</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Esta clasificación distingue las varias tablas y relaciones de clave foránea pero no nos
+ dice absolutamente todo lo que necesitamos saber sobre el modelo relacional. Para entender
+ completamente la estructura relacional y las características de rendimiento, debemos considerar
+ la estructura de la clave primaria que es usada por Hibernate para actualizar o borrar filas de
+ colección. Esto sugiere la siguiente clasificación:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>colecciones indexadas</para>
+ </listitem>
+ <listitem>
+ <para>conjuntos (sets)</para>
+ </listitem>
+ <listitem>
+ <para>bolsas (bags)</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Todas las colecciones indexadas (mapas, listas, arrays) tienen una clave primaria
+ consistente de las columnas <literal><key></literal> y <literal><index></literal>.
+ En este caso las actualizaciones de colecciones son usualmente extremadamente eficientes.
+ La clave primaria puede ser indexada fácilmente y una fila en particular puede ser localizada
+ cuando Hibernate intenta actualizarla o borrarla.
+ </para>
+
+ <para>
+ Los conjuntos (sets) tienen una clave primaria consistente en <literal><key></literal>
+ y columnas de elemento. Esto puede ser menos eficiente para algunos tipos de elemento de
+ colección, particularmente elementos compuestos o texto largo, o campos binarios. La base de datos
+ puede no ser capaz de indexar una clave primaria compleja eficientemente. Por otra parte,
+ para asociaciones uno a muchos o muchos a muchos, particularmente en el caso de identificadores
+ sintéticos, es probable que sólo sea tan eficiente. (Nota al márgen: si quieres que
+ <literal>SchemaExport</literal> realmente cree la clave primaria de un <literal><set></literal>
+ por ti, debes declarar todas las columnas como <literal>not-null="true"</literal>.)
+ </para>
+
+ <para>
+ Los mapeos de <literal><idbag></literal> definen una clave delegada, de modo que siempre
+ resulten eficientes de actualizar. De hecho, son el mejor caso.
+ </para>
+
+ <para>
+ Los bags son el peor caso. Ya que un bag permite valores de elementos duplicados y no tiene
+ ninguna columna índice, no puede definirse ninguna clave primaria. Hibernate no tiene forma de
+ distinguir entre filas duplicadas. Hibernate resuelve este problema quitando completamente
+ (en un solo <literal>DELETE</literal>) y recreando la colección siempre que cambia.
+ Esto podría ser muy ineficiente.
+ </para>
+
+ <para>
+ Nota que para una asociación uno-a-muchos, la "clave primaria" puede no ser la clave
+ primaria física de la tabla de base de datos; pero incluso en este caso, la clasificación
+ anterior es útil todavía. (Aún refleja cómo Hibernate "localiza" filas individuales de la
+ colección.)
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-collections-mostefficientupdate">
+ <title>Las listas, mapas, idbags y conjuntos son las colecciones más eficientes de actualizar</title>
+
+ <para>
+ Desde la discusión anterior, debe quedar claro que las colecciones indexadas y
+ (usualmente) los conjuntos permiten la operación más eficiente en términos de añadir,
+ quitar y actualizar elementos.
+ </para>
+
+ <para>
+ Hay, discutiblemente, una ventaja más que las colecciones indexadas tienen sobre otros
+ conjuntos para las asociaciones muchos a muchos o colecciones de valores. Debido a la
+ estructura de un <literal>Set</literal>, Hibernate ni siquiera actualiza una fila con
+ <literal>UPDATE</literal> cuando se "cambia" un elemento. Los cambios a un <literal>Set</literal>
+ siempre funcionan por medio de <literal>INSERT</literal> y <literal>DELETE</literal>
+ (de filas individuales). Una vez más, esta consideración no se aplica a las asociaciones
+ uno a muchos.
+ </para>
+
+ <para>
+ Después de observar que los arrays no pueden ser perezosos, podríamos concluir que las
+ listas, mapas e idbags son los tipos más eficientes de colecciones (no inversas), con los
+ conjuntos (sets) no muy por detrás. Se espera que los sets sean el tipo más común de colección
+ en las aplicaciones de Hibernate. Esto es debido a que la semántica de los sets es la más
+ natural en el modelo relacional.
+ </para>
+
+ <para>
+ Sin embargo, en modelos de dominio de Hibernate bien dieñados, usualmente vemos que la mayoría
+ de las colecciones son de hecho asociaciones uno-a-muchos con <literal>inverse="true"</literal>.
+ Para estas asociaciones, la actualización es manejada por el extremo muchos-a-uno de la asociación,
+ y las consideraciones de este tipo sobre el rendimiento de actualización de colecciones simplemente
+ no se aplican.
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-collections-mostefficentinverse">
+ <title>Los Bags y las listas son las colecciones inversas más eficientes</title>
+
+ <para>
+ Justo antes que tires a la zanja los bags para siempre, hay un caso en particular en el que
+ los bags son muchos más eficientes que los conjuntos. Para una colección con
+ <literal>inverse="true"</literal> (el idioma estándar de relaciones uno-a-muchos bidireccionales,
+ por ejemplo) ¡podemos añadir elementos a un bag o lista sin necesidad de inicializar (fetch)
+ los elementos del bag! Esto se debe a que <literal>Collection.add()</literal> o
+ <literal>Collection.addAll()</literal> siempre deben devolver true para un bag o <literal>List</literal>
+ (no como un <literal>Set</literal>). Esto puede hacer el siguiente código común mucho más rápido.
+ </para>
+
+ <programlisting><![CDATA[Parent p = (Parent) sess.load(Parent.class, id);
+ Child c = new Child();
+ c.setParent(p);
+ p.getChildren().add(c); //no need to fetch the collection!
+ sess.flush();]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="performance-collections-oneshotdelete">
+ <title>Borrado de un solo tiro</title>
+
+ <para>
+ Ocasionalmente, borrar los elementos de una colección uno a uno puede ser extremadamente ineficiente.
+ Hibernate no es completamente estúpido, de modo que sabe no hacer eso, en el caso de una colección
+ nueva-vacía (si has llamado a <literal>list.clear()</literal>, por ejemplo). En este caso, Hibernate
+ publicará una sola <literal>DELETE</literal>, ¡y listo!
+ </para>
+
+ <para>
+ Supón que añadimos un solo elemento a una colección de tamaño veinte y luego quitamos dos elementos.
+ Hibernate publicará una sentencia <literal>INSERT</literal> y dos sentencias <literal>DELETE</literal>
+ (a menos que la colección sea un bag). Esto es ciertamente deseable.
+ </para>
+
+ <para>
+ Sin embargo, supón que quitamos dieciocho elementos, dejando dos y luego añadimos tres nuevos elementos.
+ Hay dos formas posibles de proceder
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>borrar dieciocho filas una a una y luego insertar tres filas</para>
+ </listitem>
+ <listitem>
+ <para>quitar toda la colección (en un solo <literal>DELETE</literal> de SQL) e insertar todos los
+ cinco elementos actuales (uno a uno)</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Hibernate no es lo suficientemente inteligente para saber que la segunda opción es probablemente más
+ rápida en este caso. (Y que sería probablemente indeseable para Hibernate ser tan inteligente;
+ este comportamiento podría confundir a disparadores de base de datos, etc.)
+ </para>
+
+ <para>
+ Afortunadamente, puedes forzar este comportamiento (es decir, la segunda estrategia) en cualquier
+ momento descartando (es decir, desreferenciando) la colección original y devolviendo una colección
+ nuevamente instanciada con todos los elementos actuales. Esto puede ser muy útil y potente de vez en
+ cuando.
+ </para>
+
+ <para>
+ Por supuesto, el borrado-de-un-solo-tiro no se aplica a colecciones mapeadas
+ <literal>inverse="true"</literal>.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="performance-monitoring" revision="1">
+ <title>Monitoreando el rendimiento</title>
+
+ <para>
+ La optimización no es de mucho uso sin el monitoreo y el acceso a números de rendimiento. Hibernate provee
+ un rango completo de figuras sobre sus operaciones internas. Las estadísticas en Hibernate están disponibles
+ por <literal>SessionFactory</literal>.
+ </para>
+
+ <sect2 id="performance-monitoring-sf" revision="2">
+ <title>Monitoreando una SessionFactory</title>
+
+ <para>
+ Puedes acceder a las métricas de <literal>SessionFactory</literal> de dos formas.
+ Tu primera opción es llamar a <literal>sessionFactory.getStatistics()</literal> y
+ leer o mostrar por pantalla la <literal>Statistics</literal> por ti mismo.
+ </para>
+
+ <para>
+ Hibernate puede también usar JMX para publicar las métricas si habilitas el MBean
+ <literal>StatisticsService</literal>. Puede habilitar un solo MBean para todas tus
+ <literal>SessionFactory</literal> o una por fábrica. Mira el siguiente código para
+ ejemplos de configuración minimalistas:
+ </para>
+
+ <programlisting><![CDATA[// MBean service registration for a specific SessionFactory
+Hashtable tb = new Hashtable();
+tb.put("type", "statistics");
+tb.put("sessionFactory", "myFinancialApp");
+ObjectName on = new ObjectName("hibernate", tb); // MBean object name
+
+StatisticsService stats = new StatisticsService(); // MBean implementation
+stats.setSessionFactory(sessionFactory); // Bind the stats to a SessionFactory
+server.registerMBean(stats, on); // Register the Mbean on the server]]></programlisting>
+
+
+<programlisting><![CDATA[// MBean service registration for all SessionFactory's
+Hashtable tb = new Hashtable();
+tb.put("type", "statistics");
+tb.put("sessionFactory", "all");
+ObjectName on = new ObjectName("hibernate", tb); // MBean object name
+
+StatisticsService stats = new StatisticsService(); // MBean implementation
+server.registerMBean(stats, on); // Register the MBean on the server]]></programlisting>
+
+ <para>
+ POR HACER: Esto no tiene sentido: En el primer caso, recuperamos y usamos el MBean directamente.
+ En el segundo, debemos proporcionar el nombre JNDI en el que se guarda la fábrica de sesiones antes
+ de usarlo. Usa <literal>hibernateStatsBean.setSessionFactoryJNDIName("my/JNDI/Name")</literal>
+ </para>
+ <para>
+ Puedes (des)activar el monitoreo de una <literal>SessionFactory</literal>
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ en tiempo de configuración, establece <literal>hibernate.generate_statistics</literal> a
+ <literal>false</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+ <itemizedlist>
+ <listitem>
+ <para>
+ en tiempo de ejecución: <literal>sf.getStatistics().setStatisticsEnabled(true)</literal>
+ o <literal>hibernateStatsBean.setStatisticsEnabled(true)</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Las estadísticas pueden ser reajustadas programáticamente usando el método <literal>clear()</literal>.
+ Puede enviarse un resumen a un logger (nivel info) usando el método <literal>logSummary()</literal>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="performance-monitoring-metrics" revision="1">
+ <title>Métricas</title>
+
+ <para>
+ Hibernate provee un número de métricas, desde información muy básica a la especializada
+ sólo relevante en ciertos escenarios. Todos los contadores disponibles se describen en la
+ API de la interface <literal>Statistics</literal>, en tres categorías:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Métricas relacionadas al uso general de <literal>Session</literal> usage, tales como
+ número de sesiones abiertas, conexiones JDBC recuperadas, etc,
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Métricas relacionadas a las entidades, colecciones, consultas, y cachés como un todo.
+ (también conocidas como métricas globales).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Métricas detalladas relacionadas a una entidad, colección, consulta o región de caché
+ en particular.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Por ejemplo, puedes comprobar el acceso, pérdida, y radio de colocación de entidades, colecciones
+ y consultas en el caché, y el tiempo promedio que necesita una consulta. Ten en cuenta que el número
+ de milisegundos está sujeto a aproximación en Java. Hibernate está pegado a la precisión de la JVM,
+ en algunas plataformas esto podría incuso ser tener sólo una exactitud de 10 segundos.
+ </para>
+
+ <para>
+ Se usan getters simples para acceder a las métricas globales (es decir, no pegadas a una entidad,
+ colección, región de caché, etc, en particular). Puedes acceder a las métricas de una entidad,
+ colección, región de caché en particular a través de su nombre, y a través de su representación HQL
+ o SQL para las consultas. Por favor refiérete al Javadoc de la API de <literal>Statistics</literal>,
+ <literal>EntityStatistics</literal>, <literal>CollectionStatistics</literal>,
+ <literal>SecondLevelCacheStatistics</literal>, y <literal>QueryStatistics</literal> para más información.
+ El siguiente código muestra un ejemplo sencillo:
+ </para>
+
+ <programlisting><![CDATA[Statistics stats = HibernateUtil.sessionFactory.getStatistics();
+
+double queryCacheHitCount = stats.getQueryCacheHitCount();
+double queryCacheMissCount = stats.getQueryCacheMissCount();
+double queryCacheHitRatio =
+ queryCacheHitCount / (queryCacheHitCount + queryCacheMissCount);
+
+log.info("Query Hit ratio:" + queryCacheHitRatio);
+
+EntityStatistics entityStats =
+ stats.getEntityStatistics( Cat.class.getName() );
+long changes =
+ entityStats.getInsertCount()
+ + entityStats.getUpdateCount()
+ + entityStats.getDeleteCount();
+log.info(Cat.class.getName() + " changed " + changes + "times" );]]></programlisting>
+
+ <para>
+ Para trabajar sobre todas las entidades, colecciones, consultas y regiones de cachés, puedes recuperar la
+ lista de nombres de entidades, colecciones, consultas y regiones de cachés con los siguientes métodos:
+ <literal>getQueries()</literal>, <literal>getEntityNames()</literal>,
+ <literal>getCollectionRoleNames()</literal>, y <literal>getSecondLevelCacheRegionNames()</literal>.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+</chapter>
\ No newline at end of file
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/content/persistent_classes.xml (from rev 12794, core/trunk/documentation/manual/es-ES/src/main/docbook/modules/persistent_classes.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/persistent_classes.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/persistent_classes.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,478 @@
+<chapter id="persistent-classes" revision="2">
+ <title>Clases Persistentes</title>
+
+ <para>
+ Clases presistentes son clases en una aplicación que implementan las
+ entidades del problema de negocio (por ejemplo, Customer y Order en una
+ aplicación de comercio electrónico). No todas las instancias de una
+ clase persistente se considera que estén en el estado persistente,
+ una instancia puede en cambio ser transitoria o estar separada.
+ </para>
+
+ <para>
+ Hibernate funciona mejor si las clases siguen algunas simples reglas, también
+ conocidas como el modelo de programación de Viejas Clases Java Planas
+ (Plain Old Java Object o POJO). Sin embargo, ninguna de estas reglas son
+ requerimientos rígidos. En cambio, Hibernate3 asume muy poco acerca de
+ la naturaleza de tus objetos persistentes. Puedes expresar un modelo de dominio en
+ otras formas: usando árboles de instancias de <literal>Map</literal>,
+ por ejemplo.
+ </para>
+
+ <sect1 id="persistent-classes-pojo">
+ <title>Un ejemplo simple de POJO</title>
+
+ <para>
+ La mayoría de aplicaciones Java requieren una clase
+ representando felinos.
+ </para>
+
+ <programlisting><![CDATA[package eg;
+import java.util.Set;
+import java.util.Date;
+
+public class Cat {
+ private Long id; // identifier
+
+ private Date birthdate;
+ private Color color;
+ private char sex;
+ private float weight;
+ private int litterId;
+
+ private Cat mother;
+ private Set kittens = new HashSet();
+
+ private void setId(Long id) {
+ this.id=id;
+ }
+ public Long getId() {
+ return id;
+ }
+
+ void setBirthdate(Date date) {
+ birthdate = date;
+ }
+ public Date getBirthdate() {
+ return birthdate;
+ }
+
+ void setWeight(float weight) {
+ this.weight = weight;
+ }
+ public float getWeight() {
+ return weight;
+ }
+
+ public Color getColor() {
+ return color;
+ }
+ void setColor(Color color) {
+ this.color = color;
+ }
+
+ void setSex(char sex) {
+ this.sex=sex;
+ }
+ public char getSex() {
+ return sex;
+ }
+
+ void setLitterId(int id) {
+ this.litterId = id;
+ }
+ public int getLitterId() {
+ return litterId;
+ }
+
+ void setMother(Cat mother) {
+ this.mother = mother;
+ }
+ public Cat getMother() {
+ return mother;
+ }
+ void setKittens(Set kittens) {
+ this.kittens = kittens;
+ }
+ public Set getKittens() {
+ return kittens;
+ }
+
+ // addKitten not needed by Hibernate
+ public void addKitten(Cat kitten) {
+ kitten.setMother(this);
+ kitten.setLitterId( kittens.size() );
+ kittens.add(kitten);
+ }
+}]]></programlisting>
+
+ <para>
+ Aquí hay cuatro reglas principales a seguir:
+ </para>
+
+ <sect2 id="persistent-classes-pojo-constructor" revision="1">
+ <title>Implementa un constructor sin argumentos</title>
+
+ <para>
+ <literal>Cat</literal> tiene un contructor sin argumentos. Todas las clases persistentes
+ deben tener un constructor por defecto (que puede no ser público) de modo que Hibernate
+ pueda instanciarlas usando <literal>Constructor.newInstance()</literal>. Recomendamos fuertemente tener
+ un constructor por defecto con al menos visibilidad de <emphasis>package</emphasis> para la
+ generación de proxies en tiempo de ejecución en Hibernate.
+ </para>
+ </sect2>
+
+ <sect2 id="persistent-classes-pojo-identifier" revision="2">
+ <title>Provee una propiedad identificadora (opcional)</title>
+
+ <para>
+ <literal>Cat</literal> tiene una propiedad llamada <literal>id</literal>. Esta
+ propiedad mapea a la columna clave primaria de la tabla de base de datos. La propiedad
+ podría llamarse cualquierCosa, y su tipo podría haber sido cualquier tipo
+ primitivo, cualquier tipo de "envoltura" primitivo, <literal>java.lang.String</literal>
+ o <literal>java.util.Date</literal>. (Si tu tabla de base de datos heredada tiene claves
+ compuestas, puedes incluso usar una clase definida por el usuario con propiedades de
+ estos tipos, ver la sección sobre identificadores compuestos luego.)
+ </para>
+
+ <para>
+ La propiedad identificadora es estrictamente opcional. Puedes olvidarla y dejar que Hibernate
+ siga internamente la pista de los identificadores del objeto. Sin embargo, no recomendamos esto.
+ </para>
+
+ <para>
+ De hecho, alguna funcionalidad está disponible sólo para clases que
+ declaran una propiedad identificadora:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Reasociación transitiva de objetos separados (actualizaciones o
+ fusiones en cascada) - ver <xref linkend="objectstate-transitive"/>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>Session.saveOrUpdate()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>Session.merge()</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Recomendamos que declares propiedades identificadoras nombradas-consistentemente
+ en clases persistentes. Mas aún, recomendamos que uses un tipo nulable
+ (es decir, no primitivo).
+ </para>
+ </sect2>
+
+ <sect2 id="persistent-classes-pojo-final">
+ <title>Prefiere las clases no finales (opcional)</title>
+ <para>
+ Un aspecto central de Hibernate, <emphasis>proxies</emphasis>, depende de que
+ las clases persistentes sean ya no finales, o sean ya la implementación
+ de una interface que declare todos los métodos públicos.
+ </para>
+ <para>
+ Puedes persistir con Hibernate clases <literal>final</literal> que no implementen una
+ interface, pero no serás capaz de usar proxies para recuperación perezosa
+ de asociaciones, lo que limitará tus opciones para afinar el rendimiento.
+ </para>
+ <para>
+ Debes también evitar declarar métodos <literal>public final</literal>
+ en clases non-final. Si quieres usar una clase con un método <literal>public
+ final</literal>, debes deshabilitar explícitamente el uso de proxies estableciendo
+ <literal>lazy="false"</literal>.
+ </para>
+ </sect2>
+
+ <sect2 id="persistent-classes-pojo-accessors" revision="2">
+ <title>Declara métodos de acceso y modificación para los campos persistentes (opcional)</title>
+ <para>
+ <literal>Cat</literal> declara métodos de acceso para todos sus campos persistente.
+ Muchas otras herramientas ORM persisten directamente variables de instancia. Creemos que
+ es mejor proveer una indirección entre el esquema relacional y las estructuras internas de la clase.
+ Por defecto, Hibernate persiste propiedades del estilo JavaBeans, y reconoce nombres de método
+ de la forma <literal>getFoo</literal>, <literal>isFoo</literal> y <literal>setFoo</literal>.
+ Puedes cambiar a acceso directo a campos para propiedades en particular, de ser necesario.
+ </para>
+
+ <para>
+ Las propiedades <emphasis>no</emphasis> necesitan ser declaradas públicas. Hibernate puede
+ persistir una propiedad con un par get / set <literal>protected</literal> o <literal>private</literal>.
+ </para>
+ </sect2>
+ </sect1>
+
+ <sect1 id="persistent-classes-inheritance">
+ <title>Implementando herencia</title>
+
+ <para>
+ Una subclase puede a su vez observar la primera y segunda regla. Hereda su
+ propiedad identificadora de la superclase, <literal>Cat</literal>.
+ </para>
+
+ <programlisting><![CDATA[package eg;
+
+public class DomesticCat extends Cat {
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+ protected void setName(String name) {
+ this.name=name;
+ }
+}]]></programlisting>
+ </sect1>
+
+ <sect1 id="persistent-classes-equalshashcode" revision="1">
+ <title>Implementando <literal>equals()</literal> y <literal>hashCode()</literal></title>
+
+
+ <para>
+ Tienes que sobrescribir los métodos <literal>equals()</literal> y <literal>hashCode()</literal>
+ si :
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ piensas poner instancias de clases persistentes en un <literal>Set</literal>
+ (la forma recomendada de representar asociaciones multivaluadas)
+ <emphasis>y</emphasis>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ piensas usar reasociación de instancias separadas.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Hibernate garantiza la equivalencia de identidad persistente (fila de base de datos) y
+ identidad Java sólo dentro del ámbito de una sesión en particular.
+ De modo que en el momento que mezclamos instancias recuperadas en sesiones diferentes,
+ debemos implementar <literal>equals()</literal> y <literal>hashCode()</literal> si
+ deseamos tener una semántica significativa de <literal>Set</literal>s.
+ </para>
+
+ <para>
+ La forma más obvia es implementar <literal>equals()</literal>/<literal>hashCode()</literal>
+ comparando el valor identificador de ambos objetos. Si el valor es el mismo, ambos deben ser
+ la misma fila de base de datos, por lo tanto son iguales (si ambos son agregados a un
+ <literal>Set</literal>, sólo tendremos un elemento en el <literal>Set</literal>).
+ Desafortunadamente, no podemos usar este enfoque con identificadores generados! Hibernate sólo
+ asignará valores identificadores a objetos que son persistentes, una instancia recién
+ creada no tendrá ningún valor identificador! Además, si una instancia no está
+ salvada y está actualmente en un <literal>Set</literal>, salvarla asignará un
+ valor identificador al objeto. Si <literal>equals()</literal> and <literal>hashCode()</literal>
+ están basados en el valor identificador, el código hash podría cambiar,
+ rompiendo el contrato de <literal>Set</literal>. Ver el sitio web de Hibernate para una
+ discusión completa de este problema. Observa que esto no es una incidencia de Hibernate,
+ sino la semántica normal de Java de identidad de objeto e igualdad.
+ </para>
+
+ <para>
+ Recomendamos implementar <literal>equals()</literal> y <literal>hashCode()</literal>
+ usando <emphasis>igualdad de clave de negocio (Business key equality)</emphasis>.
+ Igualdad de clave de negocio significa que el método <literal>equals()</literal>
+ compara sólo las propiedades que forman la clave de negocio, una clave que podría
+ identificar nuestra instancia en el mundo real (una clave candidata
+ <emphasis>natural</emphasis>):
+ </para>
+
+ <programlisting><![CDATA[public class Cat {
+
+ ...
+ public boolean equals(Object other) {
+ if (this == other) return true;
+ if ( !(other instanceof Cat) ) return false;
+
+ final Cat cat = (Cat) other;
+
+ if ( !cat.getLitterId().equals( getLitterId() ) ) return false;
+ if ( !cat.getMother().equals( getMother() ) ) return false;
+
+ return true;
+ }
+
+ public int hashCode() {
+ int result;
+ result = getMother().hashCode();
+ result = 29 * result + getLitterId();
+ return result;
+ }
+
+}]]></programlisting>
+
+ <para>
+ Nota que una clave de negocio no tiene que ser tan sólida como
+ una clave primaria candidata de base de datos (ver
+ <xref linkend="transactions-basics-identity"/>). Las propiedades inmutables o
+ únicas son usualmente buenas candidatas para una clave de negocio.
+ </para>
+
+ </sect1>
+
+ <sect1 id="persistent-classes-dynamicmodels">
+ <title>Modelos dinámicos</title>
+
+ <para>
+ <emphasis>Ten en cuenta que las siguientes funcionalidades están
+ consideradas actualmente experimentales y pueden cambiar en el futuro
+ cercano.</emphasis>
+ </para>
+
+ <para>
+ Las entidades persistentes no necesariamente tienen que estar representadas
+ como clases POJO o como objetos JavaBean en tiempo de ejecución. Hibernate
+ soporta además modelos dinámicos (usando <literal>Map</literal>s de
+ <literal>Map</literal>s en tiempo de ejecución) y la representación
+ de entidades como árboles de DOM4J. Con este enfoque no escribes clases
+ persistentes, sólo ficheros de mapeo.
+ </para>
+
+ <para>
+ Por defecto, Hibernate funciona en modo POJO normal. Puedes establecer una
+ representación de entidad por defecto para una <literal>SessionFactory</literal>
+ en particular usando la opción de configuración
+ <literal>default_entity_mode</literal>
+ (ver <xref linkend="configuration-optional-properties"/>).
+ </para>
+
+ <para>
+ Los siguientes ejemplos demuestran la representación usando
+ <literal>Map</literal>s. Primero, en el fichero de mapeo,
+ tiene que declararse un <literal>entity-name</literal> en vez de
+ (o como agregado a) un nombre de clase:
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class entity-name="Customer">
+
+ <id name="id"
+ type="long"
+ column="ID">
+ <generator class="sequence"/>
+ </id>
+
+ <property name="name"
+ column="NAME"
+ type="string"/>
+
+ <property name="address"
+ column="ADDRESS"
+ type="string"/>
+
+ <many-to-one name="organization"
+ column="ORGANIZATION_ID"
+ class="Organization"/>
+
+ <bag name="orders"
+ inverse="true"
+ lazy="false"
+ cascade="all">
+ <key column="CUSTOMER_ID"/>
+ <one-to-many class="Order"/>
+ </bag>
+
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Ten en cuenta que aunque las asociaciones se declaran usando nombres
+ de clase objetivo, el tipo objetivo de una asociación puede
+ ser además una entidad dinámica en vez de un POJO.
+ </para>
+
+ <para>
+ Después de establecer el modo de entidad por defecto a
+ <literal>dynamic-map</literal> para la <literal>SessionFactory</literal>,
+ podemos trabajar en tiempo de ejecución con <literal>Map</literal>s
+ de <literal>Map</literal>s:
+ </para>
+
+ <programlisting><![CDATA[Session s = openSession();
+Transaction tx = s.beginTransaction();
+Session s = openSession();
+
+// Create a customer
+Map david = new HashMap();
+david.put("name", "David");
+
+// Create an organization
+Map foobar = new HashMap();
+foobar.put("name", "Foobar Inc.");
+
+// Link both
+david.put("organization", foobar);
+
+// Save both
+s.save("Customer", david);
+s.save("Organization", foobar);
+
+tx.commit();
+s.close();]]></programlisting>
+
+ <para>
+ Las ventajas de un mapeo dinámico es rápido tiempo de ciclo
+ de prototipado sin la necesidad de implementación de clases de entidad.
+ Sin embargo, pierdes chequeo de tipos en tiempo de compilación y
+ muy probablemente tratarás con muchas excepciones en tiempo de ejecución.
+ Gracias al mapeo de Hibernate, el esquema de base de datos puede estar facilmente
+ sano y normalizado, permitiendo agregar una implementación apropiada del
+ modelo de dominio más tarde.
+ </para>
+
+ <para>
+ Los modos de representación de entidad pueden ser establecidos
+ por <literal>Session</literal>:
+ </para>
+
+ <programlisting><![CDATA[Session dynamicSession = pojoSession.getSession(EntityMode.MAP);
+
+// Create a customer
+Map david = new HashMap();
+david.put("name", "David");
+dynamicSession.save("Customer", david);
+...
+dynamicSession.flush();
+dynamicSession.close()
+...
+// Continue on pojoSession
+]]></programlisting>
+
+
+ <para>
+ Por favor, ten en cuenta que la llamada a <literal>getSession()</literal>
+ usando un <literal>EntityMode</literal> está en la API de
+ <literal>Session</literal>, no en la de <literal>SessionFactory</literal>.
+ De esta forma, la nueva <literal>Session</literal> comparte la conexión
+ JDBC, transacción y otra información de contexto. Esto significa
+ que no tienes que llamar a <literal>flush()</literal> ni a <literal>close()</literal>
+ en la <literal>Session</literal> secundaria, y tembién dejar el manejo
+ de la transacción y de la conexión a la unidad de trabajo primaria.
+ </para>
+
+ <para>
+ Puede encontrarse más información sobre las capacidades de
+ representación XML en <xref linkend="xml"/>.
+ </para>
+
+ </sect1>
+
+ <para>
+ PORHACER: Documentar el framework de extensiones del usuario en los paquetes
+ de propiedad y proxies.
+ </para>
+
+</chapter>
+
Added: core/trunk/documentation/manual/es-ES/src/main/docbook/content/preface.xml
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/preface.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/preface.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,112 @@
+<?xml version='1.0'?>
+
+<!DOCTYPE preface PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
+ <preface id="preface" revision="2">
+ <title>Prefacio</title>
+
+
+ <para>
+ Trabajar con software orientado a objetos y una base de datos relacional puede ser
+ incómodo y consumir tiempo en los entornos de empresa de hoy. Hibernate es una
+ herramienta de mapeo objeto/relacional para entornos Java. El término mapeo
+ objeto/relacional (MOR) hace referencia a la técnica de mapear una
+ representación de datos desde un modelo de objetos a un modelo de datos relacional
+ con un esquema basado en SQL.
+ </para>
+
+ <para>
+ Hibernate no sólo se encarga de mapear de clases Java a tablas de base de datos
+ (y de tipos de datos de Java a tipos de datos SQL), sino que también provee
+ facilidades de consulta y recuperación de datos y puede reducir significativamente
+ el tiempo de desarrollo que de otra forma se gasta en el manejo de los datos en SQL y JDBC.
+ </para>
+
+ <para>
+ La meta de Hibernate es relevar al desarrollador del 95 por ciento de las tareas comunes
+ relacionadas a la programación de la persistencia de los datos.
+ Hibernate puede no ser la mejor solución para aplicaciones que usan solamente
+ procedimientos almacenados para implementar la lógica de negocio en la base de
+ datos, es mas útil con modelos de dominio orientados a objetos y lógica de
+ negocio en middle-tier basada en Java. Sin embargo, Hibernate ciertamente puede ayudarte
+ a quitar o encapsular código SQL específico de vendedor y ayudará
+ con la tarea común de traducción de resultados desde una representación
+ tabular a un grafo de objetos.
+ </para>
+
+ <para>
+ Si eres nuevo en Hibernate y lo del Mapeo Objeto/Relacional o incluso en Java,
+ sigue por favor estos pasos:
+ </para>
+
+ <orderedlist>
+ <listitem>
+ <para>
+ Lee <xref linkend="quickstart"/> para un tutorial de 30 minutos, usando Tomcat.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Lee <xref linkend="architecture"/> para entender los entornos en los que
+ puede ser usado Hibernate.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Dale una mirada al directorio <literal>eg/</literal> en la distribución
+ de Hibernate, contiene una aplicación independiente simple.
+ Copia tu driver JDBC al directorio <literal>lib/</literal> y edita
+ <literal>etc/hibernate.properties</literal>, especificando los valores
+ correctos para tu base de datos. Desde línea de comandos en el
+ directorio de la distribución, tipea <literal>ant eg</literal>
+ (usando Ant), o bajo Windows, tipea <literal>build eg</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Usa esta documentación de referencia como tu fuente de información
+ primaria. Ten en consideración leer <emphasis>Java Persistence with Hibernate</emphasis>
+ (http://www.manning.com/bauer2) si necesitas mas ayuda con el diseño
+ de aplicaciones o si prefieres un tutorial paso a paso.
+ Visita también http://caveatemptor.hibernate.org y descarga la aplicación
+ de ejemplo para Java Persistence with Hibernate.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Los FAQs son respondidos en el sitio web de Hibernate.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ En el sitio web de Hibernate hay enlaces a demos de terceros, ejemplos
+ y tutoriales.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ El Area de Comunidad en el sitio web de Hibernate es una buena fuente
+ de patrones de diseño y varias soluciones de integración
+ (Tomcat, JBoss, Struts, EJB, etc.).
+ </para>
+ </listitem>
+ </orderedlist>
+
+ <para>
+ Si tienes preguntas, usa el foro de usuarios enlazado en el sitio web de Hibernate.
+ También proveemos un sistema de seguimiento JIRA para reportes de defectos y
+ peticiones de nuevas características.
+ Si estas interesado en el desarrollo de Hibernate, únete a la lista de correo
+ de desarrolladores. Si estas interesado en traducir esta documentación a tu
+ lenguaje, contáctanos en la lista de correo de desarrolladores.
+ </para>
+
+ <para>
+ A través de JBoss Inc. (see http://www.hibernate.org/SupportTraining/) hay
+ disponibilidad de soporte comercial de desarrollo, soporte de producción y
+ entrenamiento en Hibernate.
+ Hibernate es un proyecto de la suite de productos de código abierto
+ JBoss Professional.
+ </para>
+
+ </preface>
\ No newline at end of file
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/content/query_criteria.xml (from rev 12794, core/trunk/documentation/manual/es-ES/src/main/docbook/modules/query_criteria.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/query_criteria.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/query_criteria.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,431 @@
+<chapter id="querycriteria">
+ <title>Consultas por Criterios</title>
+
+ <para>
+ Acompaña a Hibernate una API de consultas por criterios intuitiva y extensible.
+ </para>
+
+ <sect1 id="querycriteria-creating">
+ <title>Creando una instancia de <literal>Criteria</literal></title>
+
+ <para>
+ La interface <literal>org.hibernate.Criteria</literal> representa una consulta contra
+ una clase persistente en particular. La <literal>Session</literal> es una fábrica de instancias
+ de <literal>Criteria</literal>.
+ </para>
+
+ <programlisting><![CDATA[Criteria crit = sess.createCriteria(Cat.class);
+crit.setMaxResults(50);
+List cats = crit.list();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="querycriteria-narrowing">
+ <title>Estrechando el conjunto resultado</title>
+
+ <para>
+ Un criterio individual de consulta es una instancia de la interface
+ <literal>org.hibernate.criterion.Criterion</literal>. La clase
+ <literal>org.hibernate.criterion.Restrictions</literal> define métodos de fábrica para obtener ciertos tipos
+ prefabricados de <literal>Criterion</literal>.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .add( Restrictions.like("name", "Fritz%") )
+ .add( Restrictions.between("weight", minWeight, maxWeight) )
+ .list();]]></programlisting>
+
+ <para>
+ Las restricciones pueden ser agrupadas lógicamente.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .add( Restrictions.like("name", "Fritz%") )
+ .add( Restrictions.or(
+ Restrictions.eq( "age", new Integer(0) ),
+ Restrictions.isNull("age")
+ ) )
+ .list();]]></programlisting>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )
+ .add( Restrictions.disjunction()
+ .add( Restrictions.isNull("age") )
+ .add( Restrictions.eq("age", new Integer(0) ) )
+ .add( Restrictions.eq("age", new Integer(1) ) )
+ .add( Restrictions.eq("age", new Integer(2) ) )
+ ) )
+ .list();]]></programlisting>
+
+ <para>
+ Hay un gran rango de tipos de criterio prefabricados (subclases de <literal>Restrictions</literal>),
+ pero uno que es especialmente útil te deja especificar SQL directamente.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .add( Restrictions.sql("lower({alias}.name) like lower(?)", "Fritz%", Hibernate.STRING) )
+ .list();]]></programlisting>
+
+ <para>
+ El sitio <literal>{alias}</literal> será remplazado por el alias de fila de la entidad consultada.
+ </para>
+
+ <para>
+ Un enfoque alternativo para obtener un criterio es tomarlo de una instancia de
+ <literal>Property</literal>. Puedes crear una <literal>Property</literal> llamando a
+ <literal>Property.forName()</literal>.
+ </para>
+
+ <programlisting><![CDATA[
+Property age = Property.forName("age");
+List cats = sess.createCriteria(Cat.class)
+ .add( Restrictions.disjunction()
+ .add( age.isNull() )
+ .add( age.eq( new Integer(0) ) )
+ .add( age.eq( new Integer(1) ) )
+ .add( age.eq( new Integer(2) ) )
+ ) )
+ .add( Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) )
+ .list();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="querycriteria-ordering">
+ <title>Ordenando los resultados</title>
+
+ <para>
+ Puedes ordenar los resultados usando <literal>org.hibernate.criterion.Order</literal>.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .add( Restrictions.like("name", "F%")
+ .addOrder( Order.asc("name") )
+ .addOrder( Order.desc("age") )
+ .setMaxResults(50)
+ .list();]]></programlisting>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .add( Property.forName("name").like("F%") )
+ .addOrder( Property.forName("name").asc() )
+ .addOrder( Property.forName("age").desc() )
+ .setMaxResults(50)
+ .list();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="querycriteria-associations">
+ <title>Asociaciones</title>
+
+ <para>
+ Puedes especificar fácilmente restricciones sobre las entidades relacionadas al navegar asociaciones
+ usando <literal>createCriteria()</literal>.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .add( Restrictions.like("name", "F%")
+ .createCriteria("kittens")
+ .add( Restrictions.like("name", "F%")
+ .list();]]></programlisting>
+
+ <para>
+ nota que el segundo <literal>createCriteria()</literal> devuelve una nueva instancia de
+ <literal>Criteria</literal>, que hace referencia a los elementos de la colección
+ <literal>kittens</literal>.
+ </para>
+
+ <para>
+ La siguiente forma alternativa es útil en ciertas circunstancias.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .createAlias("kittens", "kt")
+ .createAlias("mate", "mt")
+ .add( Restrictions.eqProperty("kt.name", "mt.name") )
+ .list();]]></programlisting>
+
+ <para>
+ (<literal>createAlias()</literal> no crea una nueva instancia de
+ <literal>Criteria</literal>.)
+ </para>
+
+ <para>
+ ¡Observa que las colecciones de gatitos tenidas por las instancias de <literal>Cat</literal> devueltas
+ por las dos consultas previas <emphasis>no</emphasis> están prefiltradas por los criterios! Si deseas
+ recuperar sólo los gatitos que emparejen los criterios, debes usar <literal>returnMaps()</literal>.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .createCriteria("kittens", "kt")
+ .add( Restrictions.eq("name", "F%") )
+ .returnMaps()
+ .list();
+Iterator iter = cats.iterator();
+while ( iter.hasNext() ) {
+ Map map = (Map) iter.next();
+ Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS);
+ Cat kitten = (Cat) map.get("kt");
+}]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="querycriteria-dynamicfetching" revision="1">
+ <title>Recuperación dinámica de asociaciones</title>
+
+ <para>
+ Puedes especificar la semántica de recuperación de asociaciones en tiempo de ejecución usando
+ <literal>setFetchMode()</literal>.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createCriteria(Cat.class)
+ .add( Restrictions.like("name", "Fritz%") )
+ .setFetchMode("mate", FetchMode.EAGER)
+ .setFetchMode("kittens", FetchMode.EAGER)
+ .list();]]></programlisting>
+
+ <para>
+ Esta consulta recuperará tanto <literal>mate</literal> como <literal>kittens</literal> por
+ unión exterior (outer join). Ver <xref linkend="performance-fetching"/> para más información.
+ </para>
+
+ </sect1>
+
+ <sect1 id="querycriteria-examples">
+ <title>Consultas por ejemplos</title>
+
+ <para>
+ La clase <literal>org.hibernate.criterion.Example</literal> te permite construir un criterio de consulta
+ a partir de una instancia dada.
+ </para>
+
+ <programlisting><![CDATA[Cat cat = new Cat();
+cat.setSex('F');
+cat.setColor(Color.BLACK);
+List results = session.createCriteria(Cat.class)
+ .add( Example.create(cat) )
+ .list();]]></programlisting>
+
+ <para>
+ Las propiedades de versión, los identificadores y las asociaciones son ignorados. Por defecto,
+ las propiedades valuadas a nulo son excluídas.
+ </para>
+
+ <para>
+ Puedes ajustar cómo se aplica el <literal>Example</literal>.
+ </para>
+
+ <programlisting><![CDATA[Example example = Example.create(cat)
+ .excludeZeroes() //exclude zero valued properties
+ .excludeProperty("color") //exclude the property named "color"
+ .ignoreCase() //perform case insensitive string comparisons
+ .enableLike(); //use like for string comparisons
+List results = session.createCriteria(Cat.class)
+ .add(example)
+ .list();]]></programlisting>
+
+ <para>
+ Puedes incluso usar ejemplos para colocar criterios sobre objetos asociados.
+ </para>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+ .add( Example.create(cat) )
+ .createCriteria("mate")
+ .add( Example.create( cat.getMate() ) )
+ .list();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="querycriteria-projection">
+ <title>Proyecciones, agregación y agrupamiento</title>
+ <para>
+ La clase <literal>org.hibernate.criterion.Projections</literal> es una fábrica de instancias de
+ <literal>Projection</literal>. Aplicamos una proyección a una consulta llamando a
+ <literal>setProjection()</literal>.
+ </para>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+ .setProjection( Projections.rowCount() )
+ .add( Restrictions.eq("color", Color.BLACK) )
+ .list();]]></programlisting>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+ .setProjection( Projections.projectionList()
+ .add( Projections.rowCount() )
+ .add( Projections.avg("weight") )
+ .add( Projections.max("weight") )
+ .add( Projections.groupProperty("color") )
+ )
+ .list();]]></programlisting>
+
+ <para>
+ No es necesario ningún "group by" explícito en una consulta por criterios.
+ Ciertos tipos de proyecciones son definidos para ser <emphasis>proyecciones agrupadas</emphasis>,
+ que además aparecen en la cláusula SQL <literal>group by</literal>.
+ </para>
+
+ <para>
+ Puede opcionalmente asignarse un alias a una proyección, de modo que el valor proyectado pueda
+ ser referido en restricciones u ordenamientos. Aquí hay dos formas diferentes de hacer esto:
+ </para>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+ .setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) )
+ .addOrder( Order.asc("colr") )
+ .list();]]></programlisting>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+ .setProjection( Projections.groupProperty("color").as("colr") )
+ .addOrder( Order.asc("colr") )
+ .list();]]></programlisting>
+
+ <para>
+ Los métodos <literal>alias()</literal> y <literal>as()</literal> simplemente envuelven una instancia
+ de proyección en otra instancia de <literal>Projection</literal> con alias. Como un atajo, puedes asignar
+ un alias cuando agregas la proyección a una lista de proyecciones:
+ </para>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+ .setProjection( Projections.projectionList()
+ .add( Projections.rowCount(), "catCountByColor" )
+ .add( Projections.avg("weight"), "avgWeight" )
+ .add( Projections.max("weight"), "maxWeight" )
+ .add( Projections.groupProperty("color"), "color" )
+ )
+ .addOrder( Order.desc("catCountByColor") )
+ .addOrder( Order.desc("avgWeight") )
+ .list();]]></programlisting>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Domestic.class, "cat")
+ .createAlias("kittens", "kit")
+ .setProjection( Projections.projectionList()
+ .add( Projections.property("cat.name"), "catName" )
+ .add( Projections.property("kit.name"), "kitName" )
+ )
+ .addOrder( Order.asc("catName") )
+ .addOrder( Order.asc("kitName") )
+ .list();]]></programlisting>
+
+ <para>
+ Puedes también usar <literal>Property.forName()</literal> para expresar proyecciones:
+ </para>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+ .setProjection( Property.forName("name") )
+ .add( Property.forName("color").eq(Color.BLACK) )
+ .list();]]></programlisting>
+
+ <programlisting><![CDATA[List results = session.createCriteria(Cat.class)
+ .setProjection( Projections.projectionList()
+ .add( Projections.rowCount().as("catCountByColor") )
+ .add( Property.forName("weight").avg().as("avgWeight") )
+ .add( Property.forName("weight").max().as("maxWeight") )
+ .add( Property.forName("color").group().as("color" )
+ )
+ .addOrder( Order.desc("catCountByColor") )
+ .addOrder( Order.desc("avgWeight") )
+ .list();]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="querycriteria-detachedqueries">
+ <title>Consultas y subconsultas separadas</title>
+ <para>
+ La clase <literal>DetachedCriteria</literal> te deja crear una consulta fuera del ámbito de una sesión,
+ y entonces ejecutarla luego usando alguna <literal>Session</literal> arbitraria.
+ </para>
+
+ <programlisting><![CDATA[DetachedCriteria query = DetachedCriteria.forClass(Cat.class)
+ .add( Property.forName("sex").eq('F') );
+
+Session session = ....;
+Transaction txn = session.beginTransaction();
+List results = query.getExecutableCriteria(session).setMaxResults(100).list();
+txn.commit();
+session.close();]]></programlisting>
+
+ <para>
+ También una <literal>DetachedCriteria</literal> puede usarse para expresar una subconsulta.
+ Las instancias de Criterion implicando subconsultas pueden obtenerse vía <literal>Subqueries</literal> o
+ <literal>Property</literal>.
+ </para>
+
+ <programlisting><![CDATA[DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)
+ .setProjection( Property.forName("weight").avg() );
+session.createCriteria(Cat.class)
+ .add( Property.forName("weight").gt(avgWeight) )
+ .list();]]></programlisting>
+
+ <programlisting><![CDATA[DetachedCriteria weights = DetachedCriteria.forClass(Cat.class)
+ .setProjection( Property.forName("weight") );
+session.createCriteria(Cat.class)
+ .add( Subqueries.geAll("weight", weights) )
+ .list();]]></programlisting>
+
+ <para>
+ Incluso son posibles las subconsultas correlacionadas:
+ </para>
+
+ <programlisting><![CDATA[DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2")
+ .setProjection( Property.forName("weight").avg() )
+ .add( Property.forName("cat2.sex").eqProperty("cat.sex") );
+session.createCriteria(Cat.class, "cat")
+ .add( Property.forName("weight").gt(avgWeightForSex) )
+ .list();]]></programlisting>
+
+ </sect1>
+
+ <!--TODO: ResultSetTransformer + aliasing. AliasToBeanTransformer allow returning arbitrary
+ user objects - similar to setResultClass in JDO2. General use of ResultTransformer
+ could also be explained. -->
+
+ <sect1 id="query-criteria-naturalid">
+ <title>Consultas por identificador natural</title>
+
+ <para>
+ Para la mayoría de consultas, incluyendo las consultas por criterios, el caché de consulta no es
+ muy eficiente, debido a que la invalidación del caché de consulta ocurre demasiado frecuentemente.
+ Sin embargo, hay un tipo especial de consulta donde podemos optimizar el algoritmo de invalidación
+ de caché: búsquedas por una clave natural constante. En algunas aplicaciones, este tipo de consulta,
+ ocurre frecuentemente. La API de criterios brinda especial provisión para este caso de uso.
+ </para>
+
+ <para>
+ Primero, debes mapear la clave natural de tu entidad usando
+ <literal><natural-id></literal>, y habilitar el uso del caché de segundo nivel.
+ </para>
+
+ <programlisting><![CDATA[<class name="User">
+ <cache usage="read-write"/>
+ <id name="id">
+ <generator class="increment"/>
+ </id>
+ <natural-id>
+ <property name="name"/>
+ <property name="org"/>
+ </natural-id>
+ <property name="password"/>
+</class>]]></programlisting>
+
+ <para>
+ Nota que esta funcionalidad no está pensada para uso con entidades con claves naturales
+ <emphasis>mutable</emphasis>.
+ </para>
+
+ <para>
+ Seguido, habilita el caché de consulta de Hibernate.
+ </para>
+
+ <para>
+ Ahora, <literal>Restrictions.naturalId()</literal> nos permite hacer uso de el algoritmo de caché
+ más eficiente.
+ </para>
+
+ <programlisting><![CDATA[session.createCriteria(User.class)
+ .add( Restrictions.naturalId()
+ .set("name", "gavin")
+ .set("org", "hb")
+ ).setCacheable(true)
+ .uniqueResult();]]></programlisting>
+
+ </sect1>
+
+</chapter>
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/content/query_hql.xml (from rev 12794, core/trunk/documentation/manual/es-ES/src/main/docbook/modules/query_hql.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/query_hql.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/query_hql.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,1107 @@
+<chapter id="queryhql">
+ <title>HQL: El Lenguaje de Consulta de Hibernate</title>
+
+ <para>
+ Hibernate está equipado con un lenguaje de consulta extremadamente potente que
+ (intencionalmente en absoluto) se parece muchísimo a SQL. Pero no te engañes por la sintaxis;
+ HQL es completamente orientado a objetos, entendiendo nociones como herencia, polimorfismo
+ y asociación.
+ </para>
+
+ <sect1 id="queryhql-casesensitivity">
+ <title>Sensibilidad a Mayúsculas</title>
+
+ <para>
+ Las consultas son insensibles a mayúsculas, excepto para nombres de clases Java y propiedades. De modo que
+ <literal>SeLeCT</literal> es lo mismo que <literal>sELEct</literal> e igual a <literal>SELECT</literal>,
+ pero <literal>org.hibernate.eg.FOO</literal> no lo es a <literal>org.hibernate.eg.Foo</literal> y
+ <literal>foo.barSet</literal> no es igual a <literal>foo.BARSET</literal>.
+ </para>
+
+ <para>
+ Este manual usa palabras clave HQL en minúsculas. Algunos usuarios encuentran las consultas con
+ palabras clave en mayúsculas más leíbles, pero encontramos esta convención fea cuando se encaja
+ en código Java.
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-from">
+ <title>La cláusula from</title>
+
+ <para>
+ La consulta más simple posible de Hibernate es de la forma:
+ </para>
+
+ <programlisting><![CDATA[from eg.Cat]]></programlisting>
+
+ <para>
+ que simplemente devuelve todas las instancias de la clase <literal>eg.Cat</literal>.
+ Usualmente no necesitamos cualificar el nombre de la clase, ya que <literal>auto-import</literal>
+ está por defecto. De modo que casi siempre escribimos solamente:
+ </para>
+
+ <programlisting><![CDATA[from Cat]]></programlisting>
+
+ <para>
+ La mayoría del tiempo, necesitarás asignar un <emphasis>alias</emphasis>, ya que querrás referirte al
+ <literal>Cat</literal> en otras partes de la consulta.
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat]]></programlisting>
+
+ <para>
+ Esta consulta asigna el alias <literal>cat</literal> a las instancias de <literal>Cat</literal>,
+ de modo que podríamos usar ese alias luego en la consulta. La palabra clave <literal>as</literal>
+ es opcional; también podríamos escribir:
+ </para>
+
+ <programlisting><![CDATA[from Cat cat]]></programlisting>
+
+ <para>
+ Pueden aparecer múltiples clases, resultando en un producto cartesiano o unión "cruzada" (cross join).
+ </para>
+
+ <programlisting><![CDATA[from Formula, Parameter]]></programlisting>
+ <programlisting><![CDATA[from Formula as form, Parameter as param]]></programlisting>
+
+ <para>
+ Se considera buena práctica el nombrar los alias de consulta usando una inicial en minúsculas,
+ consistente con los estándares de nombrado de Java para variables locales
+ (por ejemplo, <literal>domesticCat</literal>).
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-joins" revision="1">
+ <title>Asociaciones y uniones (joins)</title>
+
+ <para>
+ Podemos también asignar aliases a entidades asociadas, e incluso a elementos de una colección de valores,
+ usando una <literal>join</literal>.
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat
+ inner join cat.mate as mate
+ left outer join cat.kittens as kitten]]></programlisting>
+
+ <programlisting><![CDATA[from Cat as cat left join cat.mate.kittens as kittens]]></programlisting>
+
+ <programlisting><![CDATA[from Formula form full join form.parameter param]]></programlisting>
+
+ <para>
+ Los tipos de join soportados son prestados de ANSI SQL
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>inner join</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>left outer join</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>right outer join</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>full join</literal> (no útil usualmente)
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Las construcciones <literal>inner join</literal>, <literal>left outer join</literal> y
+ <literal>right outer join</literal> pueden ser abreviadas.
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat
+ join cat.mate as mate
+ left join cat.kittens as kitten]]></programlisting>
+
+ <para>
+ Puedes proveer condiciones de unión extra usando la palabra clave <literal>with</literal> de HQL.
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat
+ left join cat.kittens as kitten
+ with kitten.bodyWeight > 10.0]]></programlisting>
+
+ <para>
+ En adición, un "fetch" join permite a las asociaciones o colecciones de valores ser inicializadas
+ junto a sus objetos padres, usando una sola selección. Esto es particularmente útil en el case de una
+ colección. Efectivamente sobrescribe el outer join y las declaraciones perezosas (lazy) del fichero
+ de mapeo para asociaciones y colecciones. Ver <xref linkend="performance-fetching"/> para más
+ información.
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat
+ inner join fetch cat.mate
+ left join fetch cat.kittens]]></programlisting>
+
+ <para>
+ Usualmente a un fetch join no se necesita asignársele un alias, porque los objetos asociados no deben
+ ser usados en la cláusula <literal>where</literal> (ni en cualquier otra cláusula). Además, los objetos
+ asociados no son devueltos directamente en los resultados de consulta. En cambio, pueden ser accedidos
+ vía el objeto padre. La única razón por la que necesitaríamos un alias es estamos uniendo recursivamente
+ otra colección:
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat
+ inner join fetch cat.mate
+ left join fetch cat.kittens child
+ left join fetch child.kittens]]></programlisting>
+
+ <para>
+ Nota que la construcción <literal>fetch</literal> no puede usarse en consultas llamadas usando
+ <literal>scroll()</literal> o <literal>iterate()</literal>. Ni debe usarse <literal>fetch</literal>
+ junto con <literal>setMaxResults()</literal> o <literal>setFirstResult()</literal>. Tampoco puede usarse
+ <literal>fetch</literal> junto a una condición <literal>with</literal> ad hoc. Es posible crear
+ un producto cartesiano trayendo por join más de una colección en una colección, así que ten cuidado en
+ este caso. Traer por join múltiples roles de colección también da a veces resultados inesperados para mapeos
+ de bag, así que sé cuidadoso sobre cómo formular tus consultas en este caso. Finalmente, nota que
+ <literal>full join fetch</literal> y <literal>right join fetch</literal> no son significativos.
+ </para>
+
+ <para>
+ Si estás usando recuperación perezosa a nivel de propiedad (con instrumentación de bytecode), es posible
+ forzar a Hibernate a traer las propiedades perezosas inmediatamente (en la primera consulta) usando
+ <literal>fetch all properties</literal>.
+ </para>
+
+ <programlisting><![CDATA[from Document fetch all properties order by name]]></programlisting>
+ <programlisting><![CDATA[from Document doc fetch all properties where lower(doc.name) like '%cats%']]></programlisting>
+
+ </sect1>
+
+ <sect1 id="queryhql-select">
+ <title>La cláusula select</title>
+
+ <para>
+ La cláusula <literal>select</literal> escoge qué objetos y propiedades devolver in el conjunto resultado
+ de la consulta. Considera:
+ </para>
+
+ <programlisting><![CDATA[select mate
+from Cat as cat
+ inner join cat.mate as mate]]></programlisting>
+
+ <para>
+ La consulta seleccionará <literal>mate</literal>s de otros <literal>Cat</literal>s.
+ Realmente, puedes expresar esta consulta en un forma más compacta como:
+ </para>
+
+ <programlisting><![CDATA[select cat.mate from Cat cat]]></programlisting>
+
+ <para>
+ Las consultas pueden devolver propiedades de cualquier tipo de valor incluyendo propiedades de
+ tipo componente:
+ </para>
+
+ <programlisting><![CDATA[select cat.name from DomesticCat cat
+where cat.name like 'fri%']]></programlisting>
+
+ <programlisting><![CDATA[select cust.name.firstName from Customer as cust]]></programlisting>
+
+ <para>
+ Las consultas pueden devolver múltiples objetos y/o propiedades como un array de tipo
+ <literal>Object[]</literal>,
+ </para>
+
+ <programlisting><![CDATA[select mother, offspr, mate.name
+from DomesticCat as mother
+ inner join mother.mate as mate
+ left outer join mother.kittens as offspr]]></programlisting>
+
+ <para>
+ o como una <literal>List</literal>,
+ </para>
+
+ <programlisting><![CDATA[select new list(mother, offspr, mate.name)
+from DomesticCat as mother
+ inner join mother.mate as mate
+ left outer join mother.kittens as offspr]]></programlisting>
+
+ <para>
+ o como un objeto real Java de tipo seguro,
+ </para>
+
+ <programlisting><![CDATA[select new Family(mother, mate, offspr)
+from DomesticCat as mother
+ join mother.mate as mate
+ left join mother.kittens as offspr]]></programlisting>
+
+ <para>
+ asumiendo que la clase <literal>Family</literal> tiene un constructor apropiado.
+ </para>
+
+ <para>
+ Puedes asignar aliases para seleccionar expresiones usando <literal>as</literal>:
+ </para>
+
+ <programlisting><![CDATA[select max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n
+from Cat cat]]></programlisting>
+
+ <para>
+ Esto es lo más útil cuando se usa junto con <literal>select new map</literal>:
+ </para>
+
+ <programlisting><![CDATA[select new map( max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n )
+from Cat cat]]></programlisting>
+
+ <para>
+ Esta consulta devuelve un <literal>Map</literal> de aliases a valores seleccionados.
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-aggregation">
+ <title>Funciones de agregación</title>
+
+ <para>
+ Las consultas HQL pueden incluso devolver resultados de funciones de agregación sobre propiedades:
+ </para>
+
+ <programlisting><![CDATA[select avg(cat.weight), sum(cat.weight), max(cat.weight), count(cat)
+from Cat cat]]></programlisting>
+
+<!-- NO LONGER SUPPORTED
+ <para>
+ Collections may also appear inside aggregate functions in the <literal>select</literal>
+ clause.
+ </para>
+
+ <programlisting><![CDATA[select cat, count( elements(cat.kittens) )
+from Cat cat group by cat]]></programlisting>
+-->
+
+ <para>
+ Las funciones de agregación soportadas son
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>avg(...), sum(...), min(...), max(...)</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>count(*)</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>count(...), count(distinct ...), count(all...)</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Puedes usar operadores aritméticos, concatenación, y funciones SQL reconocidas en la cláusula select:
+ </para>
+
+ <programlisting><![CDATA[select cat.weight + sum(kitten.weight)
+from Cat cat
+ join cat.kittens kitten
+group by cat.id, cat.weight]]></programlisting>
+
+ <programlisting><![CDATA[select firstName||' '||initial||' '||upper(lastName) from Person]]></programlisting>
+
+ <para>
+ Las palabras clave <literal>distinct</literal> y <literal>all</literal> pueden ser usadas y tienen las misma
+ semántica que en SQL.
+ </para>
+
+ <programlisting><![CDATA[select distinct cat.name from Cat cat
+
+select count(distinct cat.name), count(cat) from Cat cat]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="queryhql-polymorphism">
+ <title>Consultas polimórficas</title>
+
+ <para>
+ Una consulta como:
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat]]></programlisting>
+
+ <para>
+ devuelve instancias no sólo de <literal>Cat</literal>, sino también de subclases como
+ <literal>DomesticCat</literal>. Las consultas de Hibernate pueden mencionar <emphasis>cualquier</emphasis>
+ clase o interface Java en la cláusula <literal>from</literal>. La consulta devolverá instancias de todas
+ las clases persistentes que extiendan esa clase o implementen la interface. La siguiente consulta devolvería
+ todos los objetos persistentes.
+ </para>
+
+ <programlisting><![CDATA[from java.lang.Object o]]></programlisting>
+
+ <para>
+ La interface <literal>Named</literal> podría ser implementada por varias clases persistentes:
+ </para>
+
+ <programlisting><![CDATA[from Named n, Named m where n.name = m.name]]></programlisting>
+
+ <para>
+ Nota que estas dos últimas consultas requerirán más de un <literal>SELECT</literal> SQL. Esto significa
+ que la cláusula <literal>order by</literal> no ordenará correctamente todo el conjunto resultado.
+ (Significa además que no puedes llamar estas consulta usando <literal>Query.scroll()</literal>.)
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-where">
+ <title>La cláusula where</title>
+
+ <para>
+ La cláusula where te permite estrechar la lista de instancias devueltas. Si no existe ningún alias.
+ puedes referirte a las propiedades por nombre:
+ </para>
+
+ <programlisting><![CDATA[from Cat where name='Fritz']]></programlisting>
+
+ <para>
+ Si existe un alias, usan un nombre cualificado de propiedad:
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat where cat.name='Fritz']]></programlisting>
+
+ <para>
+ devuelve las instancias de <literal>Cat</literal> llamadas 'Fritz'.
+ </para>
+
+ <programlisting><![CDATA[select foo
+from Foo foo, Bar bar
+where foo.startDate = bar.date]]></programlisting>
+
+ <para>
+ devolverá todas las instancias de <literal>Foo</literal> para las cuales exista una instancia
+ de <literal>bar</literal> con una propiedad <literal>date</literal> igual a la propiedad
+ <literal>startDate</literal> del <literal>Foo</literal>. Las expresiones de ruta compuestas hacen
+ la cláusula <literal>where</literal> extremadamente potente. Considera:
+ </para>
+
+ <programlisting><![CDATA[from Cat cat where cat.mate.name is not null]]></programlisting>
+
+ <para>
+ Esta consulta se traduce en una consulta SQL con una unión de tabla (interna). Si fueses a escribir algo como
+ </para>
+
+ <programlisting><![CDATA[from Foo foo
+where foo.bar.baz.customer.address.city is not null]]></programlisting>
+
+ <para>
+ terminarías con una consulta que requeriría cuatro uniones de tablas en SQL.
+ </para>
+
+ <para>
+ El operador <literal>=</literal> puede ser usado para comparar no sólo propiedades, sino también instancias:
+ </para>
+
+ <programlisting><![CDATA[from Cat cat, Cat rival where cat.mate = rival.mate]]></programlisting>
+
+ <programlisting><![CDATA[select cat, mate
+from Cat cat, Cat mate
+where cat.mate = mate]]></programlisting>
+
+ <para>
+ La propiedad especial (en minúsculas) <literal>id</literal> puede ser usada para referenciar el identificador
+ único de un objeto. (También puedes usar su nombre de propiedad.)
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat where cat.id = 123
+
+from Cat as cat where cat.mate.id = 69]]></programlisting>
+
+ <para>
+ La segunda consulta es eficiente. ¡No se requiere ninguna unión de tablas!
+ </para>
+
+ <para>
+ También pueden ser usadas las propiedades de identificadores compuestos. Supón que <literal>Person</literal>
+ tiene un identificador compuesto consistente en <literal>country</literal> y <literal>medicareNumber</literal>.
+ </para>
+
+ <programlisting><![CDATA[from bank.Person person
+where person.id.country = 'AU'
+ and person.id.medicareNumber = 123456]]></programlisting>
+
+ <programlisting><![CDATA[from bank.Account account
+where account.owner.id.country = 'AU'
+ and account.owner.id.medicareNumber = 123456]]></programlisting>
+
+ <para>
+ Una vez más, la segunda consulta no requiere ninguna unión de tablas.
+ </para>
+
+ <para>
+ Asimismo, la propiedad especial <literal>class</literal> acccede al valor discriminador de una instancia en
+ el caso de persistencia polimórfica. Un nombre de clase Java embebido en la cláusula where será
+ traducido a su valor discriminador.
+ </para>
+
+ <programlisting><![CDATA[from Cat cat where cat.class = DomesticCat]]></programlisting>
+
+ <para>
+ Puedes también especificar propiedades de componentes o tipos compuestos de usuario (y de componentes
+ de componentes, etc). Nunca intentes usar una expresión de ruta que termine en una propiedad de tipo
+ componente (al contrario de una propiedad de un componente). Por ejemplo, si <literal>store.owner</literal>
+ es una entidad con un componente <literal>address</literal>
+ </para>
+
+ <programlisting><![CDATA[store.owner.address.city // okay
+store.owner.address // error!]]></programlisting>
+
+ <para>
+ Un tipo "any" tiene las propiedades especiales <literal>id</literal> y <literal>class</literal>,
+ permiténdonos expresar un join en la siguiente forma (donde <literal>AuditLog.item</literal> es una
+ propiedad mapeada con <literal><any></literal>).
+ </para>
+
+ <programlisting><![CDATA[from AuditLog log, Payment payment
+where log.item.class = 'Payment' and log.item.id = payment.id]]></programlisting>
+
+ <para>
+ Nota que <literal>log.item.class</literal> y <literal>payment.class</literal> harían referencia a
+ los valores de columnas de base de datos completamente diferentes en la consulta anterior.
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-expressions">
+ <title>Expresiones</title>
+
+ <para>
+ Las expresiones permitidas en la cláusula <literal>where</literal> incluyen la mayoría del tipo de cosas
+ que podrías escribir en SQL:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ operadores matemáticos <literal>+, -, *, /</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ operadores de comparación binarios <literal>=, >=, <=, <>, !=, like</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ operadores lógicos <literal>and, or, not</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Paréntesis <literal>( )</literal>, indicando agrupación
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>in</literal>,
+ <literal>not in</literal>,
+ <literal>between</literal>,
+ <literal>is null</literal>,
+ <literal>is not null</literal>,
+ <literal>is empty</literal>,
+ <literal>is not empty</literal>,
+ <literal>member of</literal> y
+ <literal>not member of</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Caso "simple", <literal>case ... when ... then ... else ... end</literal>,
+ y caso "buscado", <literal>case when ... then ... else ... end</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ concatenación de cadenas <literal>...||...</literal> o <literal>concat(...,...)</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>current_date()</literal>, <literal>current_time()</literal>,
+ <literal>current_timestamp()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>second(...)</literal>, <literal>minute(...)</literal>,
+ <literal>hour(...)</literal>, <literal>day(...)</literal>,
+ <literal>month(...)</literal>, <literal>year(...)</literal>,
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Cualquier función u operador definido por EJB-QL 3.0: <literal>substring(), trim(),
+ lower(), upper(), length(), locate(), abs(), sqrt(), bit_length(), mod()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>coalesce()</literal> y <literal>nullif()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>str()</literal> para convertir valores numéricos o temporales a una cadena legible.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>cast(... as ...)</literal>, donde el segundo argumento es el nombre de un tipo Hibernate
+ , y <literal>extract(... from ...)</literal> si <literal>cast()</literal> y
+ <literal>extract()</literal> fuesen soportados por la base de datos subyacente.
+ </para>
+ </listitem>
+
+
+ <listitem>
+ <para>
+ la función <literal>index()</literal> de HQL, que se aplica a alias de una colección
+ indexada unida.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ funciones de HQL que tomen expresiones de ruta valuadas en colecciones: <literal>size(),
+ minelement(), maxelement(), minindex(), maxindex()</literal>, junto a las funciones especiales
+ <literal>elements()</literal> and <literal>indices</literal> que pueden ser cuantificadas usando
+ <literal>some, all, exists, any, in</literal>.
+ </para>
+ </listitem>
+
+ <listitem>
+ <para>
+ Cualquier función escalar SQL soportada por la base de datos como <literal>sign()</literal>,
+ <literal>trunc()</literal>, <literal>rtrim()</literal>, <literal>sin()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ parámetros posicionales JDBC <literal>?</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ parámetros con nombre <literal>:name</literal>, <literal>:start_date</literal>, <literal>:x1</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ literales SQL <literal>'foo'</literal>, <literal>69</literal>, <literal>6.66E+2</literal>,
+ <literal>'1970-01-01 10:00:01.0'</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ constantes Java <literal>public static final</literal> <literal>eg.Color.TABBY</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ <literal>in</literal> y <literal>between</literal> pueden usarse como sigue:
+ </para>
+
+ <programlisting><![CDATA[from DomesticCat cat where cat.name between 'A' and 'B']]></programlisting>
+
+ <programlisting><![CDATA[from DomesticCat cat where cat.name in ( 'Foo', 'Bar', 'Baz' )]]></programlisting>
+
+ <para>
+ y pueden escribirse las formas negadas
+ </para>
+
+ <programlisting><![CDATA[from DomesticCat cat where cat.name not between 'A' and 'B']]></programlisting>
+
+ <programlisting><![CDATA[from DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )]]></programlisting>
+
+ <para>
+ Asimismo, <literal>is null</literal> y <literal>is not null</literal> pueden ser usadas para comprobar
+ valores nulos.
+ </para>
+
+ <para>
+ Los booleanos pueden ser fácilmente usados en expresiones declarando substituciones de consulta HQL
+ en la configuración de Hibernate:
+ </para>
+
+ <programlisting><![CDATA[<property name="hibernate.query.substitutions">true 1, false 0</property>]]></programlisting>
+
+ <para>
+ Esto remplazará las palabras clave <literal>true</literal> y <literal>false</literal> con los literales
+ <literal>1</literal> y <literal>0</literal> en el SQL traducido de este HQL:
+ </para>
+
+ <programlisting><![CDATA[from Cat cat where cat.alive = true]]></programlisting>
+
+ <para>
+ Puedes comprobar el tamaño de una colección con la propiedad especial <literal>size</literal>, o la función
+ especial <literal>size()</literal>.
+ </para>
+
+ <programlisting><![CDATA[from Cat cat where cat.kittens.size > 0]]></programlisting>
+
+ <programlisting><![CDATA[from Cat cat where size(cat.kittens) > 0]]></programlisting>
+
+ <para>
+ Para colecciones indexadas, puedes referirte a los índices máximo y mínimo usando las funciones
+ <literal>minindex</literal> y <literal>maxindex</literal>. Similarmente, puedes referirte a los elementos
+ máximo y mínimo de una colección de tipo básico usando las funciones
+ <literal>minelement</literal> y <literal>maxelement</literal>.
+ </para>
+
+ <programlisting><![CDATA[from Calendar cal where maxelement(cal.holidays) > current_date]]></programlisting>
+
+ <programlisting><![CDATA[from Order order where maxindex(order.items) > 100]]></programlisting>
+
+ <programlisting><![CDATA[from Order order where minelement(order.items) > 10000]]></programlisting>
+
+ <para>
+ Las funciones SQL <literal>any, some, all, exists, in</literal> están soportadas cuando se les pasa
+ el conjunto de elementos o índices de una colección (funciones <literal>elements</literal> y
+ <literal>indices</literal>) o el resultado de una subconsulta (ver debajo).
+ </para>
+
+ <programlisting><![CDATA[select mother from Cat as mother, Cat as kit
+where kit in elements(foo.kittens)]]></programlisting>
+
+ <programlisting><![CDATA[select p from NameList list, Person p
+where p.name = some elements(list.names)]]></programlisting>
+
+ <programlisting><![CDATA[from Cat cat where exists elements(cat.kittens)]]></programlisting>
+
+ <programlisting><![CDATA[from Player p where 3 > all elements(p.scores)]]></programlisting>
+
+ <programlisting><![CDATA[from Show show where 'fizard' in indices(show.acts)]]></programlisting>
+
+ <para>
+ Nota que estas construcciones - <literal>size</literal>, <literal>elements</literal>,
+ <literal>indices</literal>, <literal>minindex</literal>, <literal>maxindex</literal>,
+ <literal>minelement</literal>, <literal>maxelement</literal> - pueden ser usadas solamente
+ en la cláusula where en Hibernate3.
+ </para>
+
+ <para>
+ Los elementos de colecciones indexadas (arrays, listas, mapas) pueden ser referidos por índice
+ (en una cláusula where solamente):
+ </para>
+
+ <programlisting><![CDATA[from Order order where order.items[0].id = 1234]]></programlisting>
+
+ <programlisting><![CDATA[select person from Person person, Calendar calendar
+where calendar.holidays['national day'] = person.birthDay
+ and person.nationality.calendar = calendar]]></programlisting>
+
+ <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ order.deliveredItemIndices[0] ] = item and order.id = 11]]></programlisting>
+
+ <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ maxindex(order.items) ] = item and order.id = 11]]></programlisting>
+
+ <para>
+ La expresión dentro de <literal>[]</literal> puede incluso ser una expresión aritmética.
+ </para>
+
+ <programlisting><![CDATA[select item from Item item, Order order
+where order.items[ size(order.items) - 1 ] = item]]></programlisting>
+
+ <para>
+ HQL provee además el función prefabricada <literal>index()</literal>, para elementos de una
+ asociación uno-a-muchos o colección de valores.
+ </para>
+
+ <programlisting><![CDATA[select item, index(item) from Order order
+ join order.items item
+where index(item) < 5]]></programlisting>
+
+ <para>
+ Pueden usarse las funciones SQL escalares soportadas por la base de datos subyacente
+ </para>
+
+ <programlisting><![CDATA[from DomesticCat cat where upper(cat.name) like 'FRI%']]></programlisting>
+
+ <para>
+ Si aún no estás convencido de todo esto, piensa cuánto más largo y menos leíble sería la siguiente
+ consulta en SQL:
+ </para>
+
+ <programlisting><![CDATA[select cust
+from Product prod,
+ Store store
+ inner join store.customers cust
+where prod.name = 'widget'
+ and store.location.name in ( 'Melbourne', 'Sydney' )
+ and prod = all elements(cust.currentOrder.lineItems)]]></programlisting>
+
+ <para>
+ <emphasis>Ayuda:</emphasis> algo como
+ </para>
+
+ <programlisting><![CDATA[SELECT cust.name, cust.address, cust.phone, cust.id, cust.current_order
+FROM customers cust,
+ stores store,
+ locations loc,
+ store_customers sc,
+ product prod
+WHERE prod.name = 'widget'
+ AND store.loc_id = loc.id
+ AND loc.name IN ( 'Melbourne', 'Sydney' )
+ AND sc.store_id = store.id
+ AND sc.cust_id = cust.id
+ AND prod.id = ALL(
+ SELECT item.prod_id
+ FROM line_items item, orders o
+ WHERE item.order_id = o.id
+ AND cust.current_order = o.id
+ )]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="queryhql-ordering">
+ <title>La cláusula order by</title>
+
+ <para>
+ La lista devuelta por una consulta puede ser ordenada por cualquier propiedad de una clase devuelta
+ o componentes:
+ </para>
+
+ <programlisting><![CDATA[from DomesticCat cat
+order by cat.name asc, cat.weight desc, cat.birthdate]]></programlisting>
+
+ <para>
+ Los <literal>asc</literal> o <literal>desc</literal> opcionales indican ordenamiento ascendente o
+ descendente respectivamente.
+ </para>
+ </sect1>
+
+ <sect1 id="queryhql-grouping">
+ <title>La cláusula group by</title>
+
+ <para>
+ Una consulta que devuelve valores agregados puede ser agrupada por cualquier propiedad de una clase
+ devuelta o componentes:
+ </para>
+
+ <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat)
+from Cat cat
+group by cat.color]]></programlisting>
+
+ <programlisting><![CDATA[select foo.id, avg(name), max(name)
+from Foo foo join foo.names name
+group by foo.id]]></programlisting>
+
+ <para>
+ Se permite también una cláusula <literal>having</literal>.
+ </para>
+
+ <programlisting><![CDATA[select cat.color, sum(cat.weight), count(cat)
+from Cat cat
+group by cat.color
+having cat.color in (eg.Color.TABBY, eg.Color.BLACK)]]></programlisting>
+
+ <para>
+ Las funciones y funciones de agregación SQL están permitidas en las cláusulas
+ <literal>having</literal> y <literal>order by</literal>, si están soportadas por la base de datos
+ subyacente (por ejemplo, no en MySQL).
+ </para>
+
+ <programlisting><![CDATA[select cat
+from Cat cat
+ join cat.kittens kitten
+group by cat
+having avg(kitten.weight) > 100
+order by count(kitten) asc, sum(kitten.weight) desc]]></programlisting>
+
+ <para>
+ Nota que ni la cláusula <literal>group by</literal> ni la cláusula <literal>order by</literal> pueden
+ contener expresiones aritméticas.
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-subqueries">
+ <title>Subconsultas</title>
+
+ <para>
+ Para bases de datos que soportan subconsultas, Hibernate soporta subconsultas dentro de consultas. Una
+ subconsulta debe ser encerrada entre paréntesis (frecuentemente por una llamada a una función de agregación
+ SQL). Incluso se permiten subconsultas correlacionadas (subconsultas que hacen referencia a un alias en la
+ consulta exterior).
+ </para>
+
+ <programlisting><![CDATA[from Cat as fatcat
+where fatcat.weight > (
+ select avg(cat.weight) from DomesticCat cat
+)]]></programlisting>
+
+ <programlisting><![CDATA[from DomesticCat as cat
+where cat.name = some (
+ select name.nickName from Name as name
+)]]></programlisting>
+
+ <programlisting><![CDATA[from Cat as cat
+where not exists (
+ from Cat as mate where mate.mate = cat
+)]]></programlisting>
+
+ <programlisting><![CDATA[from DomesticCat as cat
+where cat.name not in (
+ select name.nickName from Name as name
+)]]></programlisting>
+
+ <para>
+ Para las subconsultas con más de una expresión en la lista de selección, puedes usar un constructor
+ de tuplas:
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat
+where not ( cat.name, cat.color ) in (
+ select cat.name, cat.color from DomesticCat cat
+)]]></programlisting>
+
+ <para>
+ Nota que en algunas bases de datos (pero no en Oracle o HSQL), puedes usar constructores de tuplar en
+ otros contextos, por ejemplo al consultar componentes o tipos de usuario compuestos:
+ </para>
+
+ <programlisting><![CDATA[from Person where name = ('Gavin', 'A', 'King')]]></programlisting>
+
+ <para>
+ Que es equivalente a la más verborrágica:
+ </para>
+
+ <programlisting><![CDATA[from Person where name.first = 'Gavin' and name.initial = 'A' and name.last = 'King')]]></programlisting>
+
+ <para>
+ Existen dos buenas razones por las cuales podrías no querer hacer este tipo de cosa: primero, no es
+ completamente portable entre plataformas de base de datos; segundo, la consulta ahora es dependiente
+ del orden de propiedades en el documento de mapeo.
+ </para>
+
+ </sect1>
+
+ <sect1 id="queryhql-examples">
+ <title>Ejemplos de HQL</title>
+
+ <para>
+ Las consultas de Hibernate pueden ser abolutamente potentes y complejas, De hecho, el poder del lenguaje
+ de consulta es uno de los puntos principales de venta de Hibernate. He aquí algunos consultas de ejemplo
+ muy similares a consultas que he usado en un proyecto reciente. ¡Nota que la mayoría de las consultas
+ que escribirás som mucho más simples que estas!
+ </para>
+
+ <para>
+ La siguiente consulta devuelve el order id, número de items y valor total de la orden para todas
+ las ordenes inpagas de un cliente en particular y valor total mínimo dados, ordenando los resultados
+ por valor total. Al determinar los precios, usa el catálogo actual. La consulta SQL resultante,
+ contra las tablas <literal>ORDER</literal>, <literal>ORDER_LINE</literal>, <literal>PRODUCT</literal>,
+ <literal>CATALOG</literal> and <literal>PRICE</literal> tiene cuatro joins interiores y una subselect
+ (no correlacionada).
+ </para>
+
+ <programlisting><![CDATA[select order.id, sum(price.amount), count(item)
+from Order as order
+ join order.lineItems as item
+ join item.product as product,
+ Catalog as catalog
+ join catalog.prices as price
+where order.paid = false
+ and order.customer = :customer
+ and price.product = product
+ and catalog.effectiveDate < sysdate
+ and catalog.effectiveDate >= all (
+ select cat.effectiveDate
+ from Catalog as cat
+ where cat.effectiveDate < sysdate
+ )
+group by order
+having sum(price.amount) > :minAmount
+order by sum(price.amount) desc]]></programlisting>
+
+ <para>
+ ¡Qué monstruo! Realmente, en la vida real, no estoy muy afilado en subconsultas, de modo que mi
+ consulta fue realmente algo como esto:
+ </para>
+
+ <programlisting><![CDATA[select order.id, sum(price.amount), count(item)
+from Order as order
+ join order.lineItems as item
+ join item.product as product,
+ Catalog as catalog
+ join catalog.prices as price
+where order.paid = false
+ and order.customer = :customer
+ and price.product = product
+ and catalog = :currentCatalog
+group by order
+having sum(price.amount) > :minAmount
+order by sum(price.amount) desc]]></programlisting>
+
+ <para>
+ La próxima consulta cuenta el número de pagos en cada estado, excluyendo todos los pagos
+ en el estado <literal>AWAITING_APPROVAL</literal> donde el estado más reciente fue hecho por el
+ usuario actual. Se traduce en una consulta SQL con dos joins interiores y una subselect
+ correlacionada contra las tablas <literal>PAYMENT</literal>, <literal>PAYMENT_STATUS</literal> y
+ <literal>PAYMENT_STATUS_CHANGE</literal>.
+ </para>
+
+ <programlisting><![CDATA[select count(payment), status.name
+from Payment as payment
+ join payment.currentStatus as status
+ join payment.statusChanges as statusChange
+where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
+ or (
+ statusChange.timeStamp = (
+ select max(change.timeStamp)
+ from PaymentStatusChange change
+ where change.payment = payment
+ )
+ and statusChange.user <> :currentUser
+ )
+group by status.name, status.sortOrder
+order by status.sortOrder]]></programlisting>
+
+ <para>
+ Si hubiese mapeado la colección <literal>statusChanges</literal> como una lista, en vez de un conjunto,
+ la consulta habría sido mucho más simple de escribir.
+ </para>
+
+ <programlisting><![CDATA[select count(payment), status.name
+from Payment as payment
+ join payment.currentStatus as status
+where payment.status.name <> PaymentStatus.AWAITING_APPROVAL
+ or payment.statusChanges[ maxIndex(payment.statusChanges) ].user <> :currentUser
+group by status.name, status.sortOrder
+order by status.sortOrder]]></programlisting>
+
+ <para>
+ La próxima consulta usa la función <literal>isNull()</literal> de MS SQL Server para devolver
+ todas las cuentas y pagos inpagos de la organización a la que pertenece el usuario actual.
+ Se traduce en una consulta SQL con tres joins interiores, un join exterior y una subconsulta
+ contra las tablas <literal>ACCOUNT</literal>, <literal>PAYMENT</literal>, <literal>PAYMENT_STATUS</literal>,
+ <literal>ACCOUNT_TYPE</literal>, <literal>ORGANIZATION</literal> y <literal>ORG_USER</literal>.
+ </para>
+
+ <programlisting><![CDATA[select account, payment
+from Account as account
+ left outer join account.payments as payment
+where :currentUser in elements(account.holder.users)
+ and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
+order by account.type.sortOrder, account.accountNumber, payment.dueDate]]></programlisting>
+
+ <para>
+ Para algunas bases de datos, necesitaríamos eliminar la subselect (correlacionada).
+ </para>
+
+ <programlisting><![CDATA[select account, payment
+from Account as account
+ join account.holder.users as user
+ left outer join account.payments as payment
+where :currentUser = user
+ and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
+order by account.type.sortOrder, account.accountNumber, payment.dueDate]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="queryhql-bulk">
+ <title>Sentencias UPDATE y DELETE masivas</title>
+
+ <para>
+ HQL soporta ahora sentencias UPDATE y DELETE en HQL.
+ Ver <xref linkend="batch-direct"/> para detalles.
+ </para>
+ </sect1>
+
+ <sect1 id="queryhql-tipstricks">
+ <title>Consejos y Trucos</title>
+
+ <para>
+ Puedes contar el número de resultados de una consulta sin devolverlos realmente:
+ </para>
+
+ <programlisting><![CDATA[( (Integer) session.createQuery("select count(*) from ....").iterate().next() ).intValue()]]></programlisting>
+
+ <para>
+ Para ordenar un resultado por el tamaño de una colección, usa la siguiente consulta:
+ </para>
+
+ <programlisting><![CDATA[select usr.id, usr.name
+from User as usr
+ left join usr.messages as msg
+group by usr.id, usr.name
+order by count(msg)]]></programlisting>
+
+ <para>
+ Si tu base de datos soporta subselects, puedes colocar una condición sobre el tamaño de selección
+ en la cláusula where de tu consulta:
+ </para>
+
+ <programlisting><![CDATA[from User usr where size(usr.messages) >= 1]]></programlisting>
+
+ <para>
+ Si tu base de datos no soporta subselects, usa la siguiente consulta:
+ </para>
+
+ <programlisting><![CDATA[select usr.id, usr.name
+from User usr.name
+ join usr.messages msg
+group by usr.id, usr.name
+having count(msg) >= 1]]></programlisting>
+
+ <para>
+ Como esta solución no puede devolver un <literal>User</literal> con cero mensajes debido a la unión interior,
+ la siguiente forma es también útil:
+ </para>
+
+ <programlisting><![CDATA[select usr.id, usr.name
+from User as usr
+ left join usr.messages as msg
+group by usr.id, usr.name
+having count(msg) = 0]]></programlisting>
+
+ <para>
+ Las propiedades de un JavaBean pueden ser ligadas al parámetros de consulta con nombre:
+ </para>
+
+ <programlisting><![CDATA[Query q = s.createQuery("from foo Foo as foo where foo.name=:name and foo.size=:size");
+q.setProperties(fooBean); // fooBean has getName() and getSize()
+List foos = q.list();]]></programlisting>
+
+ <para>
+ Las colecciones son paginables usando la interface <literal>Query</literal> con un filtro:
+ </para>
+
+ <programlisting><![CDATA[Query q = s.createFilter( collection, "" ); // the trivial filter
+q.setMaxResults(PAGE_SIZE);
+q.setFirstResult(PAGE_SIZE * pageNumber);
+List page = q.list();]]></programlisting>
+
+ <para>
+ Los elementos de colección pueden ser ordenados o agrupados usando un filtro de consulta:
+ </para>
+
+ <programlisting><![CDATA[Collection orderedCollection = s.filter( collection, "order by this.amount" );
+Collection counts = s.filter( collection, "select this.type, count(this) group by this.type" );]]></programlisting>
+
+ <para>
+ Puedes hallar el tamaño de una colección sin inicializarla:
+ </para>
+
+ <programlisting><![CDATA[( (Integer) session.createQuery("select count(*) from ....").iterate().next() ).intValue();]]></programlisting>
+
+ </sect1>
+
+</chapter>
+
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/content/query_sql.xml (from rev 12794, core/trunk/documentation/manual/es-ES/src/main/docbook/modules/query_sql.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/query_sql.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/query_sql.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,477 @@
+<chapter id="querysql" revision="2">
+ <title>SQL Nativo</title>
+
+ <para>
+ Puedes también expresar consultas en el dialecto SQL nativo de tu base de datos. Esto es útil si quieres
+ utilizar aspectos específicos de base de datos tal como consejos (hints) de consulta o la palabra clave
+ <literal>CONNECT</literal> en Oracle. Provee además una clara ruta de migración desde una aplicación
+ basada en SQL/JDBC directo a Hibernate.
+ </para>
+
+ <para>
+ Hibernate3 te permite especificar SQL escrito a mano (incluyendo procedimientos almacenados) para todas
+ las operaciones de creación, actualización, borrado y carga.
+ </para>
+
+ <sect1 id="querysql-creating">
+ <title>Creando una <literal>Query</literal> de SQL nativo</title>
+
+ <para>
+ Las consultas SQL se controlan por medio de la interface <literal>SQLQuery</literal>, que se obtiene
+ llamando a <literal>Session.createSQLQuery()</literal>.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createSQLQuery("select {cat.*} from cats cat")
+ .addEntity("cat", Cat.class)
+ .setMaxResults(50)
+ .list();]]></programlisting>
+
+ <para>
+ Esta consulta especificada:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ la cadena de consulta SQL, con un lugar para que Hibernate inyecte los alias de columnas
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ la entidad devuelta por la consulta, y sus alias de tablas SQL
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ El método <literal>addEntity()</literal> asocia alias de tablas SQL con clases de entidad,
+ y determina la forma del conjunto resultado de la consulta.
+ </para>
+
+ <para>
+ El método <literal>addJoin()</literal> puede ser usado para cargar asociaciones a otras entidades y
+ colecciones.
+ </para>
+
+ <programlisting><![CDATA[List cats = sess.createSQLQuery(
+ "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
+ )
+ .addEntity("cat", Cat.class)
+ .addJoin("kitten", "cat.kittens")
+ .list();]]></programlisting>
+
+ <para>
+ Una consulta SQL nativa podría devolver un valor escalar simple o una combinación de escalares y entidades.
+ </para>
+
+ <programlisting><![CDATA[Double max = (Double) sess.createSQLQuery("select max(cat.weight) as maxWeight from cats cat")
+ .addScalar("maxWeight", Hibernate.DOUBLE);
+ .uniqueResult();]]></programlisting>
+
+
+ </sect1>
+
+ <sect1 id="querysql-aliasreferences">
+ <title>Alias y referencias de propiedad</title>
+
+ <para>
+ La notación <literal>{cat.*}</literal> usada arriba es un atajo para "todas las propiedades".
+ Alternativamente, puedes listar las columnas explícitamente, pero incluso en este caso dejamos
+ que Hibernate inyecte los alias de columnas SQL para cada propiedad. El lugar para un alias de columna
+ es sólo el nombre de propiedad cualificado por el alias de la tabla. En el siguiente ejemplo,
+ recuperamos <literal>Cat</literal>s de una tabla diferente (<literal>cat_log</literal>) a una
+ declarada en los metadatos de mapeo. Nota que podríamos incluso usar los alias de propiedad en la
+ cláusula where si quisieramos.
+ </para>
+ <para>
+ La sintáxis <literal>{}</literal> <emphasis>no</emphasis> es requerida para consultas con nombre.
+ Ver <xref linkend="querysql-namedqueries"/>
+ </para>
+
+ <programlisting><![CDATA[String sql = "select cat.originalId as {cat.id}, " +
+ "cat.mateid as {cat.mate}, cat.sex as {cat.sex}, " +
+ "cat.weight*10 as {cat.weight}, cat.name as {cat.name} " +
+ "from cat_log cat where {cat.mate} = :catId"
+
+List loggedCats = sess.createSQLQuery(sql)
+ .addEntity("cat", Cat.class)
+ .setLong("catId", catId)
+ .list();]]></programlisting>
+
+ <para>
+ <emphasis>Nota:</emphasis> si listas cada propiedad explícitamente, ¡debes incluir todas las
+ propiedades de la clase <emphasis>y sus subclases</emphasis>!
+ </para>
+
+ </sect1>
+
+ <sect1 id="querysql-namedqueries" revision="2">
+ <title>Consultas SQL con nombre</title>
+
+ <para>
+ Las consultas SQL con nombre pueden definirse en el documento de mapeo y llamadas exactamente
+ en la misma forma en que a una consulta HQL con nombre. En este caso, <emphasis>no</emphasis>
+ necesitamos llamar a <literal>addEntity()</literal>.
+ </para>
+
+ <programlisting><![CDATA[<sql-query name="persons">
+ <return alias="person" class="eg.Person"/>
+ SELECT person.NAME AS {person.name},
+ person.AGE AS {person.age},
+ person.SEX AS {person.sex}
+ FROM PERSON person
+ WHERE person.NAME LIKE :namePattern
+</sql-query>]]></programlisting>
+
+ <programlisting><![CDATA[List people = sess.getNamedQuery("persons")
+ .setString("namePattern", namePattern)
+ .setMaxResults(50)
+ .list();]]></programlisting>
+
+ <para>
+ Los elementos <literal><return-join></literal> y <literal><load-collection></literal>
+ se usan para unir asociaciones y definir consultas que inicialicen colecciones, respectivamente.
+ </para>
+
+ <programlisting><![CDATA[<sql-query name="personsWith">
+ <return alias="person" class="eg.Person"/>
+ <return-join alias="address" property="person.mailingAddress"/>
+ SELECT person.NAME AS {person.name},
+ person.AGE AS {person.age},
+ person.SEX AS {person.sex},
+ address.STREET AS {address.street},
+ address.CITY AS {address.city},
+ address.STATE AS {address.state},
+ address.ZIP AS {address.zip}
+ FROM PERSON person
+ JOIN ADDRESS address
+ ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
+ WHERE person.NAME LIKE :namePattern
+</sql-query>]]></programlisting>
+
+ <para>
+ Una consulta SQL con nombre puede devolver un valor escalar. Debes especificar el alias de columna y
+ tipo Hibernate usando el elementp <literal><return-scalar></literal>:
+ </para>
+
+ <programlisting><![CDATA[<sql-query name="mySqlQuery">
+ <return-scalar column="name" type="string"/>
+ <return-scalar column="age" type="long"/>
+ SELECT p.NAME AS name,
+ p.AGE AS age,
+ FROM PERSON p WHERE p.NAME LIKE 'Hiber%'
+</sql-query>]]></programlisting>
+
+ <sect2 id="propertyresults">
+ <title>Usando return-property para especificar explícitamente nombres de columna/alias</title>
+
+ <para>
+ Con <literal><return-property></literal> puedes decirle explícitamente a Hibernate qué
+ alias de columna usar, en vez de usar la sintáxis <literal>{}</literal> para dejar que Hibernate
+ inyecte sus propios alias.
+ </para>
+
+ <programlisting><![CDATA[<sql-query name="mySqlQuery">
+ <return alias="person" class="eg.Person">
+ <return-property name="name" column="myName"/>
+ <return-property name="age" column="myAge"/>
+ <return-property name="sex" column="mySex"/>
+ </return>
+ SELECT person.NAME AS myName,
+ person.AGE AS myAge,
+ person.SEX AS mySex,
+ FROM PERSON person WHERE person.NAME LIKE :name
+</sql-query>
+]]></programlisting>
+
+ <para>
+ <literal><return-property></literal> también trabaja con múltiples columnas. Esto resuelve una
+ limitación de la sintáxis <literal>{}</literal>, la cual no puede permitir un control fino de propiedades
+ multi-columna.
+ </para>
+
+ <programlisting><![CDATA[<sql-query name="organizationCurrentEmployments">
+ <return alias="emp" class="Employment">
+ <return-property name="salary">
+ <return-column name="VALUE"/>
+ <return-column name="CURRENCY"/>
+ </return-property>
+ <return-property name="endDate" column="myEndDate"/>
+ </return>
+ SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer},
+ STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate},
+ REGIONCODE as {emp.regionCode}, EID AS {emp.id}, VALUE, CURRENCY
+ FROM EMPLOYMENT
+ WHERE EMPLOYER = :id AND ENDDATE IS NULL
+ ORDER BY STARTDATE ASC
+</sql-query>]]></programlisting>
+
+ <para>
+ Nota que en este ejemplo hemos usado <literal><return-property></literal> en combinación con
+ la sintáxis <literal>{}</literal> para inyección, permitiendo a los usuarios elejir cómo quieren
+ referirse a las columnas y propiedades.
+ </para>
+
+ <para>
+ Si tu mapeo tiene un discriminador debes usar <literal><return-discriminator></literal>
+ para especificar la columna discriminadora.
+ </para>
+ </sect2>
+
+ <sect2 id="sp_query">
+ <title>Usando procedimientos almacenados para consultar</title>
+
+ <para>
+ Hibernate3 introduce soporte para consultas vía procedimientos almacenados. Los procedimientos
+ almacenados deben devolver un conjunto resultado como el primer parámetro de salida para ser
+ capaces de funcionar con Hibernate. Un ejemplo de uno procedimiento almacenado en Oracle 9
+ o superior es así:
+ </para>
+
+ <programlisting><![CDATA[CREATE OR REPLACE FUNCTION selectAllEmployments
+ RETURN SYS_REFCURSOR
+AS
+ st_cursor SYS_REFCURSOR;
+BEGIN
+ OPEN st_cursor FOR
+ SELECT EMPLOYEE, EMPLOYER,
+ STARTDATE, ENDDATE,
+ REGIONCODE, EID, VALUE, CURRENCY
+ FROM EMPLOYMENT;
+ RETURN st_cursor;
+ END;]]></programlisting>
+
+ <para>
+ Para usar esta consulta en Hibernate necesitas mapearla por medio de una consulta con nombre.
+ </para>
+
+ <programlisting><![CDATA[<sql-query name="selectAllEmployees_SP" callable="true">
+ <return alias="emp" class="Employment">
+ <return-property name="employee" column="EMPLOYEE"/>
+ <return-property name="employer" column="EMPLOYER"/>
+ <return-property name="startDate" column="STARTDATE"/>
+ <return-property name="endDate" column="ENDDATE"/>
+ <return-property name="regionCode" column="REGIONCODE"/>
+ <return-property name="id" column="EID"/>
+ <return-property name="salary">
+ <return-column name="VALUE"/>
+ <return-column name="CURRENCY"/>
+ </return-property>
+ </return>
+ { ? = call selectAllEmployments() }
+</sql-query>]]></programlisting>
+
+ <para>
+ Nota que los procedimientos almacenados sólo devuelven escalares y entidades.
+ No están soportados <literal><return-join></literal> y <literal><load-collection></literal>.
+ </para>
+
+ <sect3 id="querysql-limits-storedprocedures">
+ <title>Reglas/limitaciones para usar procedimientos almacenados</title>
+
+ <para>
+ Para usar procedimientos almacenados con Hibernate los procedimientos tienen que seguir algunas reglas.
+ Si no siguen esas reglas no son usables por Hibernate. Si aún quisieras usar estos procedimientos
+ tendrías que ejecutarlos por medio de <literal>session.connection()</literal>. Las reglas son
+ diferentes para cada base de datos, ya que los vendedores de base de datos tienen diferentes
+ semánticas/sintáxis de procedimientos almacenados.
+ </para>
+
+ <para>
+ Las consultas de procedimientos almacenados no pueden ser paginadas con
+ <literal>setFirstResult()/setMaxResults()</literal>.
+ </para>
+
+ <para>
+ Para Oracle se aplican las siguientes reglas:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ El procedimiento debe devolver un conjunto resultado. Esto se hace devolviendo un
+ <literal>SYS_REFCURSOR</literal> en Oracle 9 o 10. En Oracle necesitas definir un
+ tipo <literal>REF CURSOR</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ La forma recomendada es <literal>{ ? = call procName(<parameters>) }</literal> o
+ <literal>{ ? = call procName }</literal> (esto es más una regla de Oracle que una regla de Hibernate).
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Para Sybase o MS SQL server se aplican las siguientes reglas:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ El procedimiento debe devolver un conjunto resultado. Nota que ya que estos servidores pueden
+ y devolverán múltiples conjuntos resultados y cuentas de actualización, Hibernate iterará
+ los resultados y tomará el primer resultado que sea un conjunto resultado como su valor
+ a devolver. Todo lo demás será descartado.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Si habilitas <literal>SET NOCOUNT ON</literal> en tu procedimiento será probablemente más
+ eficiente, pero esto no es un requerimiento.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </sect3>
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="querysql-cud">
+ <title>SQL personalizado para crear, actualizar y borrar</title>
+
+ <para>
+ Hibernate3 puede usar sentencias SQL personalizadas para las operaciones de
+ crear, actualizar y borrar. Los persistidores de clases y colecciones en Hibernate
+ ya contienen un conjunto de cadenas generadas en tiempo de configuración (insertsql,
+ deletesql, updatesql, etc.). Las etiquetas de mapeo <literal><sql-insert></literal>,
+ <literal><sql-delete></literal>, y <literal><sql-update></literal> sobrescriben
+ estas cadenas:
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id">
+ <generator class="increment"/>
+ </id>
+ <property name="name" not-null="true"/>
+ <sql-insert>INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? )</sql-insert>
+ <sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE ID=?</sql-update>
+ <sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete>
+</class>]]></programlisting>
+
+ <para>
+ El SQL se ejecuta directamente en tu base de datos, de modo que eres libre de usar cualquier
+ dialecto que quieras. Esto reducirá, por supuesto, la portabilidad de tu mapeo si usas SQL
+ específico de la base de datos.
+ </para>
+
+ <para>
+ Los procedimientos almacenados son soportados si está establecido el atributo
+ <literal>callable</literal>:
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id">
+ <generator class="increment"/>
+ </id>
+ <property name="name" not-null="true"/>
+ <sql-insert callable="true">{call createPerson (?, ?)}</sql-insert>
+ <sql-delete callable="true">{? = call deletePerson (?)}</sql-delete>
+ <sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update>
+</class>]]></programlisting>
+
+ <para>
+ El orden de los parámetros posicionales son actualmente vitales, ya que deben estar en la
+ misma secuencia en que las espera Hibernate.
+ </para>
+
+ <para>
+ Puedes ver el orden esperado habilitando el registro de depuración para el nivel
+ <literal>org.hibernate.persister.entity</literal>. Con este nivel habilitado, Hibernate
+ imprimirá el SQL estático que se usa para crear, actualizar, borrar, etc. las entidades.
+ (Para ver la secuencia esperada, recuerda no incluir tu SQL personalizado en los ficheros
+ de mapeo ya que sobrescribirán el sql estático generado por Hibernate.)
+ </para>
+
+ <para>
+ Los procedimientos almacenados son, en la mayoría de los casos (léase, mejor hacerlo que no hacerlo),
+ obligados a devolver el número de filas insertadas/actualizadas/borradas, ya que Hibernate tiene algunas
+ comprobaciones en tiempo de ejecución del éxito de la sentencia. Hibernate siempre registra el primer
+ parámetro de la sentencia como un parámetro de salida numérico para las operaciones CUD:
+ </para>
+
+ <programlisting><![CDATA[CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2)
+ RETURN NUMBER IS
+BEGIN
+
+ update PERSON
+ set
+ NAME = uname,
+ where
+ ID = uid;
+
+ return SQL%ROWCOUNT;
+
+END updatePerson;]]></programlisting>
+
+
+ </sect1>
+
+ <sect1 id="querysql-load">
+ <title>SQL personalizado para carga</title>
+
+ <para>
+ Puedes también declarar tu propias consultas SQL (o HQL) para cargar entidades:
+ </para>
+
+ <programlisting><![CDATA[<sql-query name="person">
+ <return alias="pers" class="Person" lock-mode="upgrade"/>
+ SELECT NAME AS {pers.name}, ID AS {pers.id}
+ FROM PERSON
+ WHERE ID=?
+ FOR UPDATE
+</sql-query>]]></programlisting>
+
+ <para>
+ Esto es sólo una declaración de consulta con nombrem como se ha discutido anteriormente.
+ Puedes hacer referencia a esta consulta con nombre en un mapeo de clase:
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id">
+ <generator class="increment"/>
+ </id>
+ <property name="name" not-null="true"/>
+ <loader query-ref="person"/>
+</class>]]></programlisting>
+
+ <para>
+ Esto incluso funciona con procedimientos almacenados.
+ </para>
+
+ <para>
+ Puedes incluso definit una consulta para la carga de colecciones:
+ </para>
+
+<programlisting><![CDATA[<set name="employments" inverse="true">
+ <key/>
+ <one-to-many class="Employment"/>
+ <loader query-ref="employments"/>
+</set>]]></programlisting>
+
+ <programlisting><![CDATA[<sql-query name="employments">
+ <load-collection alias="emp" role="Person.employments"/>
+ SELECT {emp.*}
+ FROM EMPLOYMENT emp
+ WHERE EMPLOYER = :id
+ ORDER BY STARTDATE ASC, EMPLOYEE ASC
+</sql-query>]]></programlisting>
+
+ <para>
+ Podrías incluso definir un cargador de entidades que cargue una colección por
+ recuperación por unión (join fetching):
+ </para>
+
+ <programlisting><![CDATA[<sql-query name="person">
+ <return alias="pers" class="Person"/>
+ <return-join alias="emp" property="pers.employments"/>
+ SELECT NAME AS {pers.*}, {emp.*}
+ FROM PERSON pers
+ LEFT OUTER JOIN EMPLOYMENT emp
+ ON pers.ID = emp.PERSON_ID
+ WHERE ID=?
+</sql-query>]]></programlisting>
+
+ </sect1>
+
+</chapter>
\ No newline at end of file
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/content/quickstart.xml (from rev 12891, core/trunk/documentation/manual/es-ES/src/main/docbook/modules/quickstart.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/quickstart.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/quickstart.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,666 @@
+<chapter id="quickstart">
+ <title>Comienzo rápido con Tomcat</title>
+
+ <sect1 id="quickstart-intro" revision="2">
+ <title>Empezando con Hibernate</title>
+
+ <para>
+ Este tutorial explica una instalación de Hibernate con el
+ contenedor de servlets Apache Tomcat (hemos usado la versión 4.1,
+ las diferencias con la 5.0 deben ser mínimas) para una aplicación
+ basada en web. Hibernate trabaja bien en un entorno manejado con
+ todos los servidores de aplicaciones J2EE importantes, o incluso en aplicaciones
+ Java independientes. El sistema de base de datos es sólo una cuestión
+ de cambiar la configuración del dialecto SQL de Hibernate y las
+ propiedades de conexión.
+ </para>
+
+ <para>
+ Primero, tenemos que copiar todas las bibliotecas requeridas a la instalación
+ de Tomcat. Usamos un contexto web separado (<literal>webapps/quickstart</literal>)
+ para este tutorial, de modo que tenemos que considerar tanto la ruta de búsqueda
+ de bibliotecas global (<literal>TOMCAT/common/lib</literal>) como también
+ el cargador de clases a nivel de contexto en <literal>webapps/quickstart/WEB-INF/lib</literal>
+ (para ficheros JAR) y <literal>webapps/quickstart/WEB-INF/classes</literal>.
+ Nos referiremos a ambos niveles de cargador de clases como el classpath global y el classpath
+ de contexto, respectivamente.
+ </para>
+
+ <para>
+ Ahora, copia las bibliotecas a los dos classpaths:
+ </para>
+
+ <orderedlist>
+ <listitem>
+ <para>
+ Copia el driver JDBC para la base de datos al classpath global. Esto se
+ requiere para el software de pool de conexiones DBCP que se distribuye
+ con Tomcat. Hibernate usa conexiones JDBC para ejecutar SQL sobre la base de
+ datos, de modo que, o bien tienes que proveer conexiones JDBC en pool,
+ o bien configurar Hibernate para que use uno de los pools soportados
+ directamente (C3P0, Proxool). Para este tutorial, copia la biblioteca
+ <literal>pg74jdbc3.jar</literal> (para PostgreSQL 7.4 y JDK 1.4) al
+ classpath del cargador global. Si quisieras usar una base de datos diferente,
+ simplemente copia su apropiado driver JDBC.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Nunca copies nada más dentro de la ruta del cargador de clases global
+ en Tomcat, o tendrás problemas con varias herramientas, incluyendo
+ Log4J, commons-logging y otras. Siempre usa el classpath de contexto para
+ cada aplicación web, esto es, copia las bibliotecas a
+ <literal>WEB-INF/lib</literal> y tus propias clases y ficheros de
+ configuración/propiedades a <literal>WEB-INF/classes</literal>.
+ Ambos directorios están a nivel del classpath de contexto por defecto.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Hibernate está empaquetado como una biblioteca JAR. El fichero
+ <literal>hibernate3.jar</literal> debe ser copiado en el classpath de contexto
+ junto a las otras clases de la aplicación. Hibernate requiere algunas
+ bibliotecas de terceros en tiempo de ejecución; éstas vienen
+ incluídas con la distribución de Hibernate en el directorio
+ <literal>lib/</literal>. Ver <xref linkend="3rdpartylibs"/>. Copia las
+ bibliotecas de terceros requeridas al classpath de contexto.
+ </para>
+ </listitem>
+ </orderedlist>
+
+ <table frame="topbot" id="3rdpartylibs">
+ <title>
+ Bibliotecas de terceros de Hibernate
+ </title>
+ <tgroup cols="2" rowsep="1" colsep="1">
+ <colspec colname="c1" colwidth="1*"/>
+ <colspec colname="c2" colwidth="2*"/>
+ <thead>
+ <row>
+ <entry align="center">
+ Biblioteca
+ </entry>
+ <entry align="center">
+ Descripción
+ </entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>
+ antlr (requerida)
+ </entry>
+ <entry>
+ Hibernate usa ANTLR para producir analizadores de consultas,
+ esta biblioteca también se necesita en tiempo de ejecución.
+ </entry>
+ </row>
+ <row>
+ <entry>
+ dom4j (requerida)
+ </entry>
+ <entry>
+ Hibernate usa dom4j para analizar ficheros de configuración
+ XML y ficheros de metadatos de mapeo XML.
+ </entry>
+ </row>
+ <row>
+ <entry>
+ CGLIB, asm (requerida)
+ </entry>
+ <entry>
+ Hibernate usa la biblioteca de generación de código
+ para aumentar las clases en tiempo de ejecución
+ (en combinación con reflección Java).
+ </entry>
+ </row>
+ <row>
+ <entry>
+ Commons Collections, Commons Logging (requeridas)
+ </entry>
+ <entry>
+ Hibernate usa varias bibliotecas de utilidad del proyecto
+ Jakarta Commons de Apache.
+ </entry>
+ </row>
+ <row>
+ <entry>
+ EHCache (requerida)
+ </entry>
+ <entry>
+ Hibernate puede usar varios provedores de caché para
+ el caché de segundo nivel. EHCache es el provedor de
+ caché por defecto si no se cambia en la configuración.
+ </entry>
+ </row>
+ <row>
+ <entry>
+ Log4j (opcional)
+ </entry>
+ <entry>
+ Hibernate usa la API de Commons Logging, que a su vez puede
+ usar Log4J como el mecanismo de logging subyacente. Si la
+ biblioteca Log4J está disponible en el directorio de
+ bibliotecas del contexto, Commons Logging usará Log4J
+ y la configuración <literal>log4j.properties</literal>
+ en el classpath de contexto. Un fichero de propiedades de ejemplo
+ para Log4J se incluye con la distribución de Hibernate.
+ Así que copia log4j.jar y el fichero de configuración
+ (de <literal>src/</literal>) a tu classpath de contexto si quieres
+ ver que ocurre tras escénas.
+ </entry>
+ </row>
+ <row>
+ <entry>
+ ¿Requerida o no?
+ </entry>
+ <entry>
+ Echa una mirada al fichero <literal>lib/README.txt</literal> en la
+ distribución de Hibernate. Esta es una lista actualizada
+ de bibliotecas de terceros distribuídas con Hibernate.
+ Encontrarás listadas ahí todas las bibliotecas
+ requeridas y opcionales (Observa que "buildtame required" significa
+ aquí para la construcción de Hibernate, no de tu
+ aplicación).
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ Ahora instalamos el pooling y modo compartido de conexiones de base de datos
+ tanto en Tomcat como Hibernate. Esto significa que Tomcat proveerá
+ conexiones JDBC en pool (usando su funcionalidad prefabricada de pooling DBCP).
+ Hibernate pide esas conexiones a través de JNDI. Alternativamente,
+ puedes dejar que Hibernate maneje el pool de conexiones. Tomcat liga su pool
+ de conexiones a JNDI; agregamos una declaración de recurso al fichero
+ de configuración principal de Tomcat, <literal>TOMCAT/conf/server.xml</literal>:
+ </para>
+
+ <programlisting><![CDATA[<Context path="/quickstart" docBase="quickstart">
+ <Resource name="jdbc/quickstart" scope="Shareable" type="javax.sql.DataSource"/>
+ <ResourceParams name="jdbc/quickstart">
+ <parameter>
+ <name>factory</name>
+ <value>org.apache.commons.dbcp.BasicDataSourceFactory</value>
+ </parameter>
+
+ <!-- DBCP database connection settings -->
+ <parameter>
+ <name>url</name>
+ <value>jdbc:postgresql://localhost/quickstart</value>
+ </parameter>
+ <parameter>
+ <name>driverClassName</name><value>org.postgresql.Driver</value>
+ </parameter>
+ <parameter>
+ <name>username</name>
+ <value>quickstart</value>
+ </parameter>
+ <parameter>
+ <name>password</name>
+ <value>secret</value>
+ </parameter>
+
+ <!-- DBCP connection pooling options -->
+ <parameter>
+ <name>maxWait</name>
+ <value>3000</value>
+ </parameter>
+ <parameter>
+ <name>maxIdle</name>
+ <value>100</value>
+ </parameter>
+ <parameter>
+ <name>maxActive</name>
+ <value>10</value>
+ </parameter>
+ </ResourceParams>
+</Context>]]></programlisting>
+
+ <para>
+ El contexto que configuramos en este ejemplo se llama <literal>quickstart</literal>,
+ su base es el directorio <literal>TOMCAT/webapp/quickstart</literal>. Para acceder
+ a cualquier servlet, llama a la ruta <literal>http://localhost:8080/quickstart</literal>
+ en tu navegador (por supuesto, agregando el nombre del servlet como se mapee en tu
+ <literal>web.xml</literal>). Puedes también ir más allá y crear
+ ahora un servlet simple que tenga un método <literal>process()</literal>
+ vacío.
+ </para>
+
+ <para>
+ Tomcat provee ahora conexiones a través de JNDI en
+ <literal>java:comp/env/jdbc/quickstart</literal>. Si tienes problemas obteniendo
+ el pool de conexiones en ejecución, refiérete a la documentación
+ de Tomcat. Si obtienes mensajes de excepción del driver JDBC, intenta instalar
+ primero el pool de conexiones JDBC sin Hibernate. Hay disponibles en la Web
+ tutoriales de Tomcat y JDBC.
+ </para>
+
+ <para>
+ Tu próximo paso es configurar Hibernate. Hibernate tiene que saber cómo
+ debe obtener conexiones JDBC. Usamos la configuración de Hibernate basada en XML.
+ El otro enfoque, usando un ficheros de propiedad, es casi equivalente pero pierde unas
+ pocas funcionalidades que sí permite la sintaxis XML. El fichero de configuración
+ XML se ubica en el classpath de contexto (<literal>WEB-INF/classes</literal>), como
+ <literal>hibernate.cfg.xml</literal>:
+ </para>
+
+ <programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+ "-//Hibernate/Hibernate Configuration DTD//EN"
+ "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+ <session-factory>
+
+ <property name="connection.datasource">java:comp/env/jdbc/quickstart</property>
+ <property name="show_sql">false</property>
+ <property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>
+
+ <!-- Mapping files -->
+ <mapping resource="Cat.hbm.xml"/>
+
+ </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+
+ <para>
+ Desactivamos el registro (logging) de comandos SQL y decimos a Hibernate
+ qué dialecto SQL de base de datos se usa y dónde obtener
+ conexiones JDBC (declarando la dirección JNDI del pool ligado a
+ Tomcat). El dialecto es una configuración requerida, las bases de
+ datos difieren en su interpretación del "estándar" de SQL.
+ Hibernate cuidará de las diferencias y viene con dialectos incluídos
+ para todas las principales bases de datos comerciales y de código
+ abierto.
+ </para>
+
+ <para>
+ Una <literal>SessionFactory</literal> es el concepto de Hibernate
+ de un almacén de datos solo. Pueden usarse múltiples
+ bases de datos creando múltiples ficheros de configuración
+ XML y creando múltiples objetos <literal>Configuration</literal>
+ y <literal>SessionFactory</literal> en tu aplicación.
+ </para>
+
+ <para>
+ El último elemento del <literal>hibernate.cfg.xml</literal>
+ declara <literal>Cat.hbm.xml</literal> como el nombre de un fichero
+ de mapeo XML para la clase persistente <literal>Cat</literal>. Este
+ fichero contiene los metadatos para el mapeo de la clase POJO
+ <literal>Cat</literal> a una tabla (o tablas) de base de datos.
+ Volveremos a este fichero pronto. Escribamos primero la clase POJO
+ y luego declaremos los metadatos de mapeo para ella.
+ </para>
+
+ </sect1>
+
+ <sect1 id="quickstart-persistentclass" revision="1">
+ <title>Primera clase persistente</title>
+
+ <para>
+ Hibernate trabaja mejor con el modelo de programación de los
+ Viejos Objetos Planos de Java (POJOs, a veces llamados Ordinarios Objetos Planos de Java)
+ para clases persistentes. Un POJO es como un JavaBean, con las propiedades
+ de la clase accesible vía métodos getter y setter,
+ encapsulando la representación interna de la interfaz publicamente
+ visible (Hibernate puede también acceder a los campos directamente, si se
+ necesita):
+ </para>
+
+ <programlisting><![CDATA[package org.hibernate.examples.quickstart;
+
+public class Cat {
+
+ private String id;
+ private String name;
+ private char sex;
+ private float weight;
+
+ public Cat() {
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ private void setId(String id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public char getSex() {
+ return sex;
+ }
+
+ public void setSex(char sex) {
+ this.sex = sex;
+ }
+
+ public float getWeight() {
+ return weight;
+ }
+
+ public void setWeight(float weight) {
+ this.weight = weight;
+ }
+
+}]]></programlisting>
+
+ <para>
+ Hibernate no está restringido en su uso de tipos de propiedad, todos
+ los tipos y tipos primitivos del JDK de Java (como <literal>String</literal>,
+ <literal>char</literal> y <literal>Date</literal>) pueden ser mapeados, incluyendo
+ clases del framework de colecciones de Java. Puedes mapearlos como valores,
+ colecciones de valores, o asociaciones a otras entidades. El <literal>id</literal>
+ es una propiedad especial que representa el identificador de base de datos (clave
+ primaria) de la clase. Es altamente recomendado para entidades como un
+ <literal>Cat</literal>. Hibernate puede usar identificadores sólo
+ internamente, pero perderíamos algo de la flexibilidad en nuestra
+ arquitectura de aplicación.
+ </para>
+
+ <para>
+ No tiene que implementarse ninguna interface especial para las clases persistentes
+ ni tienes que subclasear de una clase persistente raíz en especial. Hibernate
+ tampoco requiere ningún procesamiento en tiempo de construcción,
+ como manipulación del byte-code. Se basa solamente en reflección de Java
+ y aumentación de clases en tiempo de ejecución (a través de CGLIB).
+ De modo que, sin ninguna dependencia de la clase POJO en Hibernate, podemos mapearla
+ a una tabla de base de datos.
+ </para>
+
+ </sect1>
+
+ <sect1 id="quickstart-mapping" revision="1">
+ <title>Mapeando el gato</title>
+
+ <para>
+ El fichero de mapeo <literal>Cat.hbm.xml</literal> contiene los
+ metadatos requeridos para el mapeo objeto/relacional. Los metadatos
+ incluyen la declaración de clases persistentes y el mapeo de
+ propiedades (a columnas y relaciones de claves foráneas a otras
+ entidades) a tablas de base de datos.
+ </para>
+
+ <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping>
+
+ <class name="org.hibernate.examples.quickstart.Cat" table="CAT">
+
+ <!-- A 32 hex character is our surrogate key. It's automatically
+ generated by Hibernate with the UUID pattern. -->
+ <id name="id" type="string" unsaved-value="null" >
+ <column name="CAT_ID" sql-type="char(32)" not-null="true"/>
+ <generator class="uuid.hex"/>
+ </id>
+
+ <!-- A cat has to have a name, but it shouldn' be too long. -->
+ <property name="name">
+ <column name="NAME" length="16" not-null="true"/>
+ </property>
+
+ <property name="sex"/>
+
+ <property name="weight"/>
+
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Cada clase persistente debe tener un atributo identificador (realmente,
+ sólo las clases que representen entidades, no las clases dependientes
+ de tipo-valor, que son mapeadas como componentes de una entidad). Esta propiedad
+ es usada para distinguir los objetos persistentes: Dos gatos son iguales si
+ <literal>catA.getId().equals(catB.getId())</literal> es verdadero. Este concepto
+ se llama <emphasis>identidad de base de datos (database identity)</emphasis>.
+ Hibernate viene empaquetado con varios generadores de identificador para diferentes
+ escenarios (incluyendo generadores nativos para secuencias de base de datos, tablas
+ de identificadores alto/bajo, e identificadores asignados por aplicación).
+ Usamos el generador UUID (recomendado sólo para pruebas, pues deben
+ preferirse las claves enteras delegadas generadas por la base de datos) y
+ también especificamos la columna <literal>CAT_ID</literal> de la tabla
+ <literal>CAT</literal> para el valor identificador generado por Hibernate
+ (como una clave primaria de la tabla).
+ </para>
+
+ <para>
+ Todas las demás propiedades de <literal>Cat</literal> son mapeadas a la
+ misma tabla. En el caso de la propiedad <literal>name</literal>, la hemos mapeado
+ con una declaración explícita de columna de base de datos. Esto es
+ especialmente útil cuando el esquema de base de datos es generado
+ automáticamente (como sentencias DDL de SQL) desde la declaración
+ de mapeo con la herramienta <emphasis>SchemaExport</emphasis> de Hibernate.
+ Todas las demás propiedades son mapeadas usando la configuración
+ por defecto de Hibernate, que es lo que necesitas la mayoría del tiempo.
+ La tabla <literal>CAT</literal> en la base de datos se ve así como:
+ </para>
+
+ <programlisting><![CDATA[ Columna | Tipo | Modificadores
+--------+-----------------------+-----------
+ cat_id | character(32) | not null
+ name | character varying(16) | not null
+ sex | character(1) |
+ weight | real |
+Indexes: cat_pkey primary key btree (cat_id)]]></programlisting>
+
+ <para>
+ Ahora debes crear esta tabla manualmente en tu base de datos, y luego leer el
+ <xref linkend="toolsetguide"/> si quieres automatizar este paso con la
+ herramienta <literal>hbm2ddl</literal>. Esta herramienta puede crear un
+ DDL SQL completo, incluyendo definición de tablas, restricciones
+ personalizadas de tipo de columnas, restricciones de unicidad e índices.
+ </para>
+
+ </sect1>
+
+ <sect1 id="quickstart-playingwithcats" revision="2">
+ <title>Jugando con gatos</title>
+
+ <para>
+ Ahora estamos listos para comenzar la <literal>Session</literal> de Hibernate.
+ Es el <emphasis>manejador de persistencia</emphasis> que usamos para almacenar
+ y traer <literal>Cat</literal>s hacia y desde la base de datos. Pero primero,
+ tenemos que obtener una <literal>Session</literal> (unidad de trabajo de Hibernate)
+ de la <literal>SessionFactory</literal>:
+ </para>
+
+ <programlisting><![CDATA[SessionFactory sessionFactory =
+ new Configuration().configure().buildSessionFactory();]]></programlisting>
+
+ <para>
+ La llamada a <literal>configure()</literal> carga el fichero de
+ configuración <literal>hibernate.cfg.xml</literal> e
+ inicializa la instancia de <literal>Configuration</literal>.
+ Puedes establecer otras propiedades (e incluso cambiar los metadatos de mapeo)
+ accediendo a la <literal>Configuration</literal> <emphasis>antes</emphasis>
+ que construyas la <literal>SessionFactory</literal> (que es inmutable).
+ ¿Dónde creamos la <literal>SessionFactory</literal> y cómo
+ accedemos a ella en nuestra aplicación?
+ </para>
+
+ <para>
+ Una <literal>SessionFactory</literal> usualmente se construye una vez,
+ por ejemplo, al arrancar con un servlet <emphasis>load-on-startup</emphasis>.
+ Esto significa también que no debes mantenerla en una variable de instancia
+ en tus servlets, sino en alguna otro sitio. Además, necesitamos algún
+ tipo de <emphasis>Singleton</emphasis>, de modo que podamos acceder a la
+ <literal>SessionFactory</literal> fácilmente en el código de
+ aplicación. El siguiente enfoque mostrado resuelve ambos problemas:
+ configuración de arranque y fácil acceso a una
+ <literal>SessionFactory</literal>.
+ </para>
+
+ <para>
+ Implementamos una clase de ayuda <literal>HibernateUtil</literal>:
+ </para>
+
+ <programlisting><![CDATA[import org.hibernate.*;
+import org.hibernate.cfg.*;
+
+public class HibernateUtil {
+
+ private static Logger log = LoggerFactory.getLogger(HibernateUtil.class);
+
+ private static final SessionFactory sessionFactory;
+
+ static {
+ try {
+ // Create the SessionFactory
+ sessionFactory = new Configuration().configure().buildSessionFactory();
+ } catch (Throwable ex) {
+ // Make sure you log the exception, as it might be swallowed
+ log.error("Initial SessionFactory creation failed.", ex);
+ throw new ExceptionInInitializerError(ex);
+ }
+ }
+
+ public static final ThreadLocal session = new ThreadLocal();
+
+ public static Session currentSession() {
+ Session s = (Session) session.get();
+ // Open a new Session, if this Thread has none yet
+ if (s == null) {
+ s = sessionFactory.openSession();
+ session.set(s);
+ }
+ return s;
+ }
+
+ public static void closeSession() {
+ Session s = (Session) session.get();
+ if (s != null)
+ s.close();
+ session.set(null);
+ }
+}]]></programlisting>
+
+ <para>
+ Esta clase no sólo cuida de la <literal>SessionFactory</literal>
+ con su inicializador static, sino que además tiene una variable
+ <literal>ThreadLocal</literal> que tiene la <literal>Session</literal>
+ para la hebra actual. Asegúrate de entender el concepto Java de una
+ variable local a una hebra antes de intentar usar esta ayuda. Una clase
+ <literal>HibernateUtil</literal> más compleja y potente puede
+ encontrarse en <literal>CaveatEmptor</literal>, http://caveatemptor.hibernate.org/
+ </para>
+
+ <para>
+ Una <literal>SessionFactory</literal> es segura entre hebras, muchas hebras pueden
+ acceder a ella concurrentemente y pedirle <literal>Session</literal>s. Una
+ <literal>Session</literal> no es un objeto seguro entre hebras que representa
+ una sola unidad-de-trabajo con la base de datos. Las <literal>Session</literal>s
+ se abren desde una <literal>SessionFactory</literal> y son cerradas cuando
+ todo el trabajo está completo. Un ejemplo en el método
+ <literal>process()</literal> de tu servlet podría parecerse a esto
+ (sin manejo de excepciones):
+ </para>
+
+ <programlisting><![CDATA[Session session = HibernateUtil.currentSession();
+Transaction tx = session.beginTransaction();
+
+Cat princess = new Cat();
+princess.setName("Princess");
+princess.setSex('F');
+princess.setWeight(7.4f);
+
+session.save(princess);
+
+tx.commit();
+HibernateUtil.closeSession();]]></programlisting>
+
+ <para>
+ En una <literal>Session</literal>, cada operación de base de datos
+ ocurre dentro de una transacción que aísla las operaciones
+ de base de datos (incluso operaciones de sólo lectura).
+ Usamos la API de <literal>Transaction</literal> de Hibernate para
+ abstraer de la estrategia de transacciones subyacente (en nuestro caso,
+ transacciones JDBC). Esto permite que nuestro código sea desplegado
+ con transacciones manejadas por contenedor (usando JTA) sin cambio alguno.
+ </para>
+
+ <para>
+ Observa que puedes llamar <literal>HibernateUtil.currentSession();</literal>
+ tantas veces como quieras, siempre obtendrás la <literal>Session</literal>
+ actual de esta hebra. Tienes que asegurarte que la <literal>Session</literal>
+ sea cerrada después que se complete tu unidad-de-trabajo, ya sea en
+ código de tu servlet o en un filtro de servlet antes que la respuesta HTTP
+ sea enviada. El bonito efecto colateral de la segunda opción es la
+ fácil inicialización perezosa: la <literal>Session</literal> todavía
+ está abierta cuando se dibuja la vista, de modo que Hibernate puede cargar
+ objetos no inicializados mientras navegas tu actual grafo de objetos.
+ </para>
+
+ <para>
+ Hibernate tiene varios métodos que pueden ser usados para traer
+ objetos desde la base de datos. La forma más flexible es usando
+ el Lenguaje de Consulta de Hibernate (Hibernate Query Language o HQL),
+ que es una extensión orientada a objetos de SQL fácil de
+ aprender:
+ </para>
+
+ <programlisting><![CDATA[Transaction tx = session.beginTransaction();
+
+Query query = session.createQuery("select c from Cat as c where c.sex = :sex");
+query.setCharacter("sex", 'F');
+for (Iterator it = query.iterate(); it.hasNext();) {
+ Cat cat = (Cat) it.next();
+ out.println("Female Cat: " + cat.getName() );
+}
+
+tx.commit();]]></programlisting>
+
+ <para>
+ Hibernate también ofrece una API <emphasis>consulta por criterios</emphasis>
+ orientada a objetos que puede ser usada para formular consultas de tipo seguro.
+ Por supuesto, Hibernate usa <literal>PreparedStatement</literal>s y ligado de
+ parámetros para toda la comunicación SQL con la base de datos.
+ También puedes usar la funcionalidad de consulta SQL directa de Hibernate
+ u obtener una conexión plana de JDBC de una <literal>Session</literal>
+ en casos raros.
+ </para>
+
+ </sect1>
+
+ <sect1 id="quickstart-summary" revision="1">
+ <title>Finalmente</title>
+
+ <para>
+ Rasguñamos solamente la superficie de Hibernate en este pequeño
+ tutorial. Por favor, observa que no incluimos ningún código
+ específico de servlet en nuestros ejemplos. Tienes que crear un servlet
+ por tí mismo e insertar el código de Hibernate como lo veas
+ ubicado.
+ </para>
+
+ <para>
+ Ten en mente que Hibernate, como capa de acceso a datos, está firmemente
+ integrado dentro de tu aplicación. Usualmente, todas las otras capas dependen
+ del mecanismo de persistencia. Asegúrate de entender las implicaciones
+ de este diseño.
+ </para>
+
+ <para>
+ Para un ejemplo de aplicación más compleja, ver
+ http://caveatemptor.hibernate.org/ y echa una mirada a los
+ otros tutoriales con links en http://www.hibernate.org/Documentation
+ </para>
+
+ </sect1>
+
+</chapter>
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/content/session_api.xml (from rev 12794, core/trunk/documentation/manual/es-ES/src/main/docbook/modules/session_api.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/session_api.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/session_api.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,1224 @@
+<chapter id="objectstate">
+ <title>Trabajando con objetos</title>
+
+ <para>
+ Hibernate es una solución completa de mapeo objeto/relacional que no sólo
+ abstrae al desarrollador de los detalles del sistema de manejo de base datos
+ subyacente, sino que además ofrece <emphasis>manejo de estado</emphasis> de
+ objetos. Esto es, al contrario del manejo de <literal>sentencias</literal>
+ SQL en capas comunes de persistencia JDBC/SQL, una vista de la persistencia
+ en aplicaciones Java muy natural y orientada a objetos.
+ </para>
+
+ <para>
+ En otras palabras, los desarroladores de aplicaciones Hibernate deben siempre
+ pensar en el <emphasis>estado</emphasis> de sus objetos, y no necesariamente
+ en la ejecución de sentencias SQL. Esta parte es cuidada por Hibernate y es
+ sólo relevante para el desarrollador de la aplicación al afinar el rendimiento
+ del sistema.
+ </para>
+
+ <sect1 id="objectstate-overview">
+ <title>Estados de objeto de Hibernate</title>
+
+ <para>
+ Hibernate define y soporta los siguientes estados de objeto:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Transitorio</emphasis> - un objeto es transitorio si ha sido
+ recién instanciado usando el operador <literal>new</literal>, y no está
+ asociado a una <literal>Session</literal> de Hibernate. No tiene una
+ representación persistente en la base de datos y no se le ha asignado un
+ valor identificador. Las instancias transitorias serán destruídas por el
+ recolector de basura si la aplicación no mantiene más una referencia.
+ Usa la <literal>Session</literal> de Hibernate para hacer un objeto
+ persistente (y deja que Hibernate cuide de las sentencias SQL que necesitan
+ ejecutarse para esta transición).
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Persistente</emphasis> - una instancia persistente tiene una
+ representación en la base de datos y un valor identificador. Puede haber
+ sido salvado o cargado, sin embargo, está por definición en el ámbito de
+ una <literal>Session</literal>. Hibernate detectará cualquier cambio hecho
+ a un objeto en estado persistentey sincronizará el estado con la base de
+ datos cuando se complete la unidad de trabajo. Los desarrolladores no ejecutan
+ sentencias <literal>UPDATE</literal> manuales, o sentencias <literal>DELETE</literal>
+ cuando un objeto debe ser hecho transitorio.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Separado (detached)</emphasis> - una instancia separada es un objeto
+ que ha sido hecho persistente, pero su <literal>Session</literal> ha sido cerrada.
+ La referencia al objeto todavía es válida, por supuesto, y la instancia separada
+ podría incluso ser modificada en este estado. Una instancia separada puede ser
+ re-unida a una nueva <literal>Session</literal> en un punto posterior en el tiempo,
+ haciéndola persistente de nuevo (con todas las modificaciones). Este aspecto
+ habilita un modelo de programación para unidades de trabajo de ejecución larga
+ que requieren tiempo-para-pensar del usuario. Las llamamos <emphasis>transaccciones
+ de aplicación</emphasis>, es decir, una unidad de trabajo desde el punto de vista
+ del usuario.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Discutiremos ahora los estados y transiciones de estados (y los métodos de Hibernate que
+ disparan una transición) en más detalle:
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-makingpersistent" revision="1">
+ <title>Haciendo los objetos persistentes</title>
+
+ <para>
+ Las instancias recién instanciadas de una clase persistente son consideradas
+ <emphasis>transitorias</emphasis> por Hibernate. Podemos hacer una instancia
+ transitoria <emphasis>persistente</emphasis> asociándola con una sesión:
+ </para>
+
+ <programlisting><![CDATA[DomesticCat fritz = new DomesticCat();
+fritz.setColor(Color.GINGER);
+fritz.setSex('M');
+fritz.setName("Fritz");
+Long generatedId = (Long) sess.save(fritz);]]></programlisting>
+
+ <para>
+ Si <literal>Cat</literal> tiene un identificador generado, el identificador es
+ generado y asignado al <literal>cat</literal> cuando se llama a <literal>save()</literal>.
+ Si <literal>Cat</literal> tiene un identificador <literal>assigned</literal>,
+ o una clave compuesta, el identificador debe ser asignado a la instancia de
+ <literal>cat</literal> antes de llamar a <literal>save()</literal>. Puedes también
+ usar <literal>persist()</literal> en vez de <literal>save()</literal>, con la semántica
+ definida en el temprano borrador de EJB3.
+ </para>
+
+ <para>
+ Alternativamente, puedes asignar el identificador usando una versión sobrecargada
+ de <literal>save()</literal>.
+ </para>
+
+<programlisting><![CDATA[DomesticCat pk = new DomesticCat();
+pk.setColor(Color.TABBY);
+pk.setSex('F');
+pk.setName("PK");
+pk.setKittens( new HashSet() );
+pk.addKitten(fritz);
+sess.save( pk, new Long(1234) );]]></programlisting>
+
+ <para>
+ Si el objeto que haces persistente tiene objetos asociados (por ejemplo,
+ la colección <literal>kittens</literal> en el ejemplo anterior), estos
+ objetos pueden ser hechos persistentes en cualquier orden que quieras
+ a menos que tengas una restricción <literal>NOT NULL</literal> sobre una
+ columna clave foránea. Nunca hay riesgo de violar restricciones de clave
+ foránea. Sin embargo, podrías violar una restricción <literal>NOT NULL</literal>
+ si llamas a <literal>save()</literal> sobre objetos en orden erróneo.
+ </para>
+
+ <para>
+ Usualmente no te preocupas con este detalle, pues muy probablemente usarás
+ la funcionalidad de <emphasis>persistencia transitiva</emphasis> de Hibernate
+ para salvar los objetos asociados automáticamente. Entonces, ni siquiera ocurren
+ violaciones de restricciones <literal>NOT NULL</literal> - Hibernate cuidará de todo.
+ La persistencia transitiva se discute más adelante en este capítulo.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-loading">
+ <title>Cargando un objeto</title>
+
+ <para>
+ Los métodos <literal>load()</literal> de <literal>Session</literal> te brindan
+ una forma de traer una instancia persistente si ya saves su identificador.
+ <literal>load()</literal> toma un objeto clase y cargará el estado dentro de
+ una instancia recién instanciada de esta clase, en estado persistente.
+ </para>
+
+ <programlisting><![CDATA[Cat fritz = (Cat) sess.load(Cat.class, generatedId);]]></programlisting>
+
+<programlisting><![CDATA[// you need to wrap primitive identifiers
+long id = 1234;
+DomesticCat pk = (DomesticCat) sess.load( DomesticCat.class, new Long(id) );]]></programlisting>
+
+ <para>
+ Alternativamente, puedes cargar estado dentro de una instancia dada:
+ </para>
+
+<programlisting><![CDATA[Cat cat = new DomesticCat();
+// load pk's state into cat
+sess.load( cat, new Long(pkId) );
+Set kittens = cat.getKittens();]]></programlisting>
+
+ <para>
+ Nota que <literal>load()</literal> lanzará una excepción irrecuperable si no
+ hay una fila correspondiente en base de datos. Si la clase es mapeada con un
+ proxy, <literal>load()</literal> sólo devuelve un proxy no inicializado y no
+ llamará realmente a la base de datos hasta que invoques un método del proxy.
+ Este comportamiento es muy útil si deseas crear una asociación a un objeto
+ sin cargarlo realmente de la base de datos. Permite además que múltiples
+ instancias sean cargadas como un lote si se define <literal>batch-size</literal>
+ para el mapeo de la clase.
+ </para>
+
+ <para>
+ Si no tienes certeza que exista una fila correspondiente, debes usar el
+ método <literal>get()</literal>, que llama a la base de datos inmediatamente
+ y devuelve nulo si no existe una fila correspondiente.
+ </para>
+
+ <programlisting><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id);
+if (cat==null) {
+ cat = new Cat();
+ sess.save(cat, id);
+}
+return cat;]]></programlisting>
+
+ <para>
+ Puedes incluso cargar un objeto usando un <literal>SELECT ... FOR UPDATE</literal> de SQL,
+ usando un <literal>LockMode</literal>. Ver la documentación de la API para más
+ información.
+ </para>
+
+ <programlisting><![CDATA[Cat cat = (Cat) sess.get(Cat.class, id, LockMode.UPGRADE);]]></programlisting>
+
+ <para>
+ Ten en cuenta que <emphasis>ninguna</emphasis> instancia asociada o colección contenida es
+ selecciona <literal>FOR UPDATE</literal>, a menos que decidas especificar
+ <literal>lock</literal> o <literal>all</literal> como un estilo de cascada para la
+ asociación.
+ </para>
+
+ <para>
+ Es posible volver a cargar un objeto y todas sus colecciones en cualquier momento,
+ usando el método <literal>refresh()</literal>. Esto es útil cuando se usan disparadores de
+ base de datos para inicializar algunas de las propiedades del objeto.
+ </para>
+
+ <programlisting><![CDATA[sess.save(cat);
+sess.flush(); //force the SQL INSERT
+sess.refresh(cat); //re-read the state (after the trigger executes)]]></programlisting>
+
+ <para>
+ Una cuestión importante aparece usualmente en este punto: ¿Cuánto carga Hibernate de
+ la base de datos y cuántos <literal>SELECT</literal>s de SQL usará? Esto depende de la
+ <emphasis>estrategia de recuperación</emphasis> y se explica en <xref linkend="performance-fetching"/>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-querying" revision="1">
+ <title>Consultando</title>
+
+ <para>
+ Si no sabes los identificadores de los objetos que estás buscando,
+ necesitas una consulta. Hibernate soporta un lenguaje de consulta
+ orientado a objetos (HQL) fácil de usar pero potente. Para la creación
+ de consultas programáticas, Hibernate soporta una funcionalidad sofisticada
+ de consulta de Criteria y Example (QBC and QBE). También puedes expresar tu
+ consulta en el SQL nativo de tu base de datos, con soporte opcional de Hibernate
+ para la conversión del conjunto resultado en objetos.
+ </para>
+
+ <sect2 id="objectstate-querying-executing">
+ <title>Ejecutando consultas</title>
+
+ <para>
+ Las consultas HQL y SQL nativas son representadas con una instancia de
+ <literal>org.hibernate.Query</literal>. Esta interface ofrece métodos para
+ la ligación de parámetros, manejo del conjunto resultado, y para la
+ ejecución de la consulta real. Siempre obtienes una <literal>Query</literal>
+ usando la <literal>Session</literal> actual:
+ </para>
+
+ <programlisting><![CDATA[List cats = session.createQuery(
+ "from Cat as cat where cat.birthdate < ?")
+ .setDate(0, date)
+ .list();
+
+List mothers = session.createQuery(
+ "select mother from Cat as cat join cat.mother as mother where cat.name = ?")
+ .setString(0, name)
+ .list();
+
+List kittens = session.createQuery(
+ "from Cat as cat where cat.mother = ?")
+ .setEntity(0, pk)
+ .list();
+
+Cat mother = (Cat) session.createQuery(
+ "select cat.mother from Cat as cat where cat = ?")
+ .setEntity(0, izi)
+ .uniqueResult();]]></programlisting>
+
+ <para>
+ Una consulta se ejecuta usualmente invocando a <literal>list()</literal>,
+ el resultado de la consulta será cargado completamente dentro de una
+ colección en memoria. Las instancias de entidad traídas por una consulta
+ están en estado persistente. El método <literal>uniqueResult()</literal>
+ ofrece un atajo si sabes que tu consulta devolverá sólo un objeto.
+ </para>
+
+ <sect3 id="objectstate-querying-executing-iterate">
+ <title>Iterando los resultados</title>
+
+ <para>
+ Ocasionalmente, podrías ser capaz de lograr mejor rendimiento al ejecutar la consulta
+ usando el método <literal>iterate()</literal>. Esto sólo será en el caso que esperes
+ que las instancias reales de entidad devueltas por la consulta estén ya en la sesión
+ o caché de segundo nivel. Si todavía no están en caché, <literal>iterate()</literal>
+ será más lento que <literal>list()</literal> y podría requerir muchas llamadas a la
+ base de datos para una consulta simple, usualmente <emphasis>1</emphasis> para la
+ selección inicial que solamente devuelve identificadores, y <emphasis>n</emphasis>
+ selecciones adicionales para inicializar las instancias reales.
+ </para>
+
+ <programlisting><![CDATA[// fetch ids
+Iterator iter = sess.createQuery("from eg.Qux q order by q.likeliness").iterate();
+while ( iter.hasNext() ) {
+ Qux qux = (Qux) iter.next(); // fetch the object
+ // something we couldnt express in the query
+ if ( qux.calculateComplicatedAlgorithm() ) {
+ // delete the current instance
+ iter.remove();
+ // dont need to process the rest
+ break;
+ }
+}]]></programlisting>
+ </sect3>
+
+ <sect3 id="objectstate-querying-executing-tuples">
+ <title>Consultas que devuelven tuplas</title>
+
+ <para>
+ Las consultas de Hibernate a veces devuelven tuplas de objetos, en cuyo caso
+ cada tupla se devuelve como un array:
+ </para>
+
+ <programlisting><![CDATA[Iterator kittensAndMothers = sess.createQuery(
+ "select kitten, mother from Cat kitten join kitten.mother mother")
+ .list()
+ .iterator();
+
+while ( kittensAndMothers.hasNext() ) {
+ Object[] tuple = (Object[]) kittensAndMothers.next();
+ Cat kitten = (Cat) tuple[0];
+ Cat mother = (Cat) tuple[1];
+ ....
+}]]></programlisting>
+
+ </sect3>
+
+ <sect3 id="objectstate-querying-executing-scalar">
+ <title>Resultados escalares</title>
+
+ <para>
+ Las consultas pueden especificar una propiedad de una clase en la cláusula
+ <literal>select</literal>. Pueden incluso llamar a funciones de agregación SQL.
+ Las propiedades o agregaciones son considerados resultados "escalares"
+ (y no entidades en estado persistente).
+ </para>
+
+ <programlisting><![CDATA[Iterator results = sess.createQuery(
+ "select cat.color, min(cat.birthdate), count(cat) from Cat cat " +
+ "group by cat.color")
+ .list()
+ .iterator();
+
+while ( results.hasNext() ) {
+ Object[] row = results.next();
+ Color type = (Color) row[0];
+ Date oldest = (Date) row[1];
+ Integer count = (Integer) row[2];
+ .....
+}]]></programlisting>
+
+ </sect3>
+
+ <sect3 id="objectstate-querying-executing-parameters">
+ <title>Ligación de parámetros</title>
+
+ <para>
+ Se proveen métodos en <literal>Query</literal> para ligar valores a
+ parámetros con nombre o parámetros <literal>?</literal> de estilo JDBC.
+ <emphasis>Al contrario de JDBC, Hibernate numera los parámetros desde cero.</emphasis>
+ Los parámetros con nombre son identificadores de la forma <literal>:name</literal>
+ en la cadena de la consulta. Las ventajas de los parámetros con nombre son:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ los parámetros con nombre son insensibles al orden en que aparecen
+ en la cadena de consulta
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ pueden aparecer múltiples veces en la misma consulta
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ son auto-documentados
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <programlisting><![CDATA[//named parameter (preferred)
+Query q = sess.createQuery("from DomesticCat cat where cat.name = :name");
+q.setString("name", "Fritz");
+Iterator cats = q.iterate();]]></programlisting>
+
+ <programlisting><![CDATA[//positional parameter
+Query q = sess.createQuery("from DomesticCat cat where cat.name = ?");
+q.setString(0, "Izi");
+Iterator cats = q.iterate();]]></programlisting>
+
+ <programlisting><![CDATA[//named parameter list
+List names = new ArrayList();
+names.add("Izi");
+names.add("Fritz");
+Query q = sess.createQuery("from DomesticCat cat where cat.name in (:namesList)");
+q.setParameterList("namesList", names);
+List cats = q.list();]]></programlisting>
+
+ </sect3>
+
+ <sect3 id="objectstate-querying-executing-pagination">
+ <title>Paginación</title>
+
+ <para>
+ Si necesitas especificar límites sobre tu conjunto resultado (el número máximo de filas
+ que quieras traer y/o la primera fila que quieras traer) debes usar los métodos de la
+ interface <literal>Query</literal>:
+ </para>
+
+ <programlisting><![CDATA[Query q = sess.createQuery("from DomesticCat cat");
+q.setFirstResult(20);
+q.setMaxResults(10);
+List cats = q.list();]]></programlisting>
+
+ <para>
+ Hibernate sabe cómo traducir este límite de consulta al SQL nativo de tu
+ DBMS.
+ </para>
+
+ </sect3>
+
+ <sect3 id="objectstate-querying-executing-scrolling">
+ <title>Iteración scrollable</title>
+
+ <para>
+ Si tu driver JDBC soporta <literal>ResultSet</literal>s scrollables, la
+ interface <literal>Query</literal> puede ser usada para obtener un objeto
+ <literal>ScrollableResults</literal>, que permite una navegación flexible
+ de los resultados de consulta.
+ </para>
+
+ <programlisting><![CDATA[Query q = sess.createQuery("select cat.name, cat from DomesticCat cat " +
+ "order by cat.name");
+ScrollableResults cats = q.scroll();
+if ( cats.first() ) {
+
+ // find the first name on each page of an alphabetical list of cats by name
+ firstNamesOfPages = new ArrayList();
+ do {
+ String name = cats.getString(0);
+ firstNamesOfPages.add(name);
+ }
+ while ( cats.scroll(PAGE_SIZE) );
+
+ // Now get the first page of cats
+ pageOfCats = new ArrayList();
+ cats.beforeFirst();
+ int i=0;
+ while( ( PAGE_SIZE > i++ ) && cats.next() ) pageOfCats.add( cats.get(1) );
+
+}
+cats.close()]]></programlisting>
+
+ <para>
+ Nota que se requiere una conexión de base de datos abierta (y cursor) para esta
+ funcionalidad, usa <literal>setMaxResult()</literal>/<literal>setFirstResult()</literal>
+ si necesitas la funcionalidad de paginación fuera de línea.
+ </para>
+
+ </sect3>
+
+ <sect3 id="objectstate-querying-executing-named">
+ <title>Externalizando consultas con nombre</title>
+
+ <para>
+ Puedes además definir consultas con nombre en el documento de mapeo.
+ (Recuerda usar una sección <literal>CDATA</literal> si tu consulta
+ contiene caracteres que puedan ser interpretados como etiquetado.)
+ </para>
+
+ <programlisting><![CDATA[<query name="eg.DomesticCat.by.name.and.minimum.weight"><![CDATA[
+ from eg.DomesticCat as cat
+ where cat.name = ?
+ and cat.weight > ?
+] ]></query>]]></programlisting>
+
+ <para>
+ La ligación de parámetros y ejecución se hace programáticamente:
+ </para>
+
+ <programlisting><![CDATA[Query q = sess.getNamedQuery("eg.DomesticCat.by.name.and.minimum.weight");
+q.setString(0, name);
+q.setInt(1, minWeight);
+List cats = q.list();]]></programlisting>
+
+ <para>
+ Nota que el código real del programa es independiente del lenguaje de consulta
+ usado; puedes además definir consultas SQL nativas en metadatos, o migrar
+ consultas existentes a Hibernate colocándolas en ficheros de mapeo.
+ </para>
+
+ </sect3>
+
+ </sect2>
+
+ <sect2 id="objectstate-filtering" revision="1">
+ <title>Filtrando colecciones</title>
+ <para>
+ Un <emphasis>filtro</emphasis> de colección es un tipo especial de consulta que puede ser
+ aplicado a una colección persistente o array. La cadena de consulta puede referirse a
+ <literal>this</literal>, significando el elemento de colección actual.
+ </para>
+
+ <programlisting><![CDATA[Collection blackKittens = session.createFilter(
+ pk.getKittens(),
+ "where this.color = ?")
+ .setParameter( Color.BLACK, Hibernate.custom(ColorUserType.class) )
+ .list()
+);]]></programlisting>
+
+ <para>
+ La colección devuelta es considerada un bag, y es una copia de la colección
+ dada. La colección original no es modificada (esto es contrario a la implicación
+ del nombre "filtro", pero consistente con el comportamiento esperado).
+ </para>
+
+ <para>
+ Observa que los filtros no requieren una cláusula <literal>from</literal> (aunque pueden
+ tener uno si se requiere). Los filtros no están limitados a devolver los elementos de
+ colección por sí mismos.
+ </para>
+
+ <programlisting><![CDATA[Collection blackKittenMates = session.createFilter(
+ pk.getKittens(),
+ "select this.mate where this.color = eg.Color.BLACK.intValue")
+ .list();]]></programlisting>
+
+ <para>
+ Incluso una consulta de filtro vacío es útil, por ejemplo, para cargar un
+ subconjunto de elementos en una colección enorme:
+ </para>
+
+ <programlisting><![CDATA[Collection tenKittens = session.createFilter(
+ mother.getKittens(), "")
+ .setFirstResult(0).setMaxResults(10)
+ .list();]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="objecstate-querying-criteria" revision="1">
+ <title>Consultas de criterios</title>
+
+ <para>
+ HQL es extremadamente potente pero algunos desarrolladores prefieren construir
+ consultas dinámicamente usando una API orientada a objetos, en vez construir
+ cadenas de consulta. Hibernate provee una API intuitiva de consulta <literal>Criteria</literal>
+ para estos casos:
+ </para>
+
+ <programlisting><![CDATA[Criteria crit = session.createCriteria(Cat.class);
+crit.add( Restrictions.eq( "color", eg.Color.BLACK ) );
+crit.setMaxResults(10);
+List cats = crit.list();]]></programlisting>
+
+ <para>
+ Las APIs de <literal>Criteria</literal> y la asociada <literal>Example</literal>
+ son discutidas en más detalle en <xref linkend="querycriteria"/>.
+ </para>
+
+ </sect2>
+
+ <sect2 id="objectstate-querying-nativesql" revision="2">
+ <title>Consultas en SQL nativo</title>
+
+ <para>
+ Puedes expresar una consulta en SQL, usando <literal>createSQLQuery()</literal> y
+ dejando que Hibernate cuide del mapeo de los conjuntos resultado a objetos.
+ Nota que puedes llamar en cualquier momento a <literal>session.connection()</literal> y
+ usar la <literal>Connection</literal> JDBC directamente. Si eliges usar la API de
+ Hibernate, debes encerrar los alias de SQL entre llaves:
+ </para>
+
+ <programlisting><![CDATA[List cats = session.createSQLQuery("SELECT {cat.*} FROM CAT {cat} WHERE ROWNUM<10")
+ .addEntity("cat", Cat.class)
+.list();]]></programlisting>
+
+ <programlisting><![CDATA[List cats = session.createSQLQuery(
+ "SELECT {cat}.ID AS {cat.id}, {cat}.SEX AS {cat.sex}, " +
+ "{cat}.MATE AS {cat.mate}, {cat}.SUBCLASS AS {cat.class}, ... " +
+ "FROM CAT {cat} WHERE ROWNUM<10")
+ .addEntity("cat", Cat.class)
+.list()]]></programlisting>
+
+ <para>
+ Las consultas SQL pueden contener parámetros con nombre y posicionales, al igual que
+ las consultas de Hibernate. Puede encontrarse más información sobre consultas en SQL
+ nativo en <xref linkend="querysql"/>.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="objectstate-modifying" revision="1">
+ <title>Modificando objetos persistentes</title>
+
+ <para>
+ Las <emphasis>instancias persistentes transaccionales</emphasis> (es decir, objetos cargados,
+ creados o consultados por la <literal>Session</literal>) pueden ser manipulados por la
+ aplicación y cualquier cambio al estado persistente será persistido cuando la <literal>Session</literal>
+ sea <emphasis>limpiada (flushed)</emphasis> (discutido más adelante en este capítulo). No hay
+ necesidad de llamar un método en particular (como <literal>update()</literal>, que tiene un
+ propósito diferente) para hacer persistentes tus modificaciones. De modo que la forma más
+ directa de actualizar el estado de un objeto es cargarlo con <literal>load()</literal>,
+ y entonces manipularlo directamente, mientras la <literal>Session</literal> está abierta:
+ </para>
+
+ <programlisting><![CDATA[DomesticCat cat = (DomesticCat) sess.load( Cat.class, new Long(69) );
+cat.setName("PK");
+sess.flush(); // changes to cat are automatically detected and persisted]]></programlisting>
+
+ <para>
+ A veces este modelo de programación es ineficiente pues podría requerir una
+ <literal>SELECT</literal> de SQL (para cargar un objeto) y un <literal>UPDATE</literal>
+ de SQL (para hacer persistentes sus datos actualizados) en la misma sesión. Por lo tanto,
+ Hibernate ofrece un enfoque alternativo, usando instancias separadas (detached).
+ </para>
+
+ <para>
+ <emphasis>Nota que Hibernate no ofreve su propia API para ejecución directa de
+ sentencias <literal>UPDATE</literal> o <literal>DELETE</literal>. Hibernate es un
+ servicio de <emphasis>gestión de estado</emphasis>, no tienes que pensar en
+ <literal>sentencias</literal> para usarlo. JDBC es una API perfecta para ejecutar
+ sentencias SQL; puedes obtener una <literal>Connection</literal> JDBC en cualquier
+ momento llamando a <literal>session.connection()</literal>. Además, la noción de
+ operaciones masivas entra en conflicto con el mapeo objeto/relacional en aplicaciones
+ en línea orientadas al procesamiento de transacciones. Versiones futuras de Hibernate
+ pueden, sin embargo, proveer funciones de operación masiva especiales. Ver
+ <xref linkend="batch"/> por algunos trucos de operación en lote (batch) posibles.
+ </emphasis>
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-detached" revision="2">
+ <title>Modificando objetos separados</title>
+
+ <para>
+ Muchas aplicaciones necesitan recuperar un objeto en una transacción, enviarla
+ a la capa de UI para su manipulación, y entonces salvar los cambios en una nueva
+ transacción. Las aplicaciones que usan este tipo de enfoque en un entorno de
+ alta concurrencia usualmente usan datos versionados para asegurar el aislamiento
+ de la unidad de trabajo "larga".
+ </para>
+
+ <para>
+ Hibernate soporta este modelo al proveer re-unión de instancias separadas usando
+ los métodos <literal>Session.update()</literal> o <literal>Session.merge()</literal>:
+ </para>
+
+ <programlisting><![CDATA[// in the first session
+Cat cat = (Cat) firstSession.load(Cat.class, catId);
+Cat potentialMate = new Cat();
+firstSession.save(potentialMate);
+
+// in a higher layer of the application
+cat.setMate(potentialMate);
+
+// later, in a new session
+secondSession.update(cat); // update cat
+secondSession.update(mate); // update mate]]></programlisting>
+
+ <para>
+ Si el <literal>Cat</literal> con identificador <literal>catId</literal> ya hubiera
+ sido cargado por <literal>secondSession</literal> cuando la aplicación intentó
+ volver a unirlo, se habría lanzado una excepción.
+ </para>
+
+ <para>
+ Usa <literal>update()</literal> si no estás seguro que la sesión tenga
+ una instancia ya persistente con el mismo identificador, y <literal>merge()</literal>
+ si quieres fusionar tus modificaciones en cualquier momento sin consideración del
+ estado de la sesión. En otras palabras, <literal>update()</literal> es usualmente
+ el primer método que llamarías en una sesión fresca, asegurando que la re-unión de
+ tus instancias separadas es la primera operación que se ejecuta.
+ </para>
+
+ <para>
+ La aplicación debe actualizar individualmente las instancias separadas alcanzables
+ por la instancia separada dada llamando a <literal>update()</literal>, si y
+ <emphasis>sólo</emphasis> si quiere que sus estados sean también actualizados.
+ Esto puede, por supuesto, ser automatizado usando <emphasis>persistencia transitiva</emphasis>,
+ ver <xref linkend="objectstate-transitive"/>.
+ </para>
+
+ <para>
+ El método <literal>lock()</literal> también permite a una aplicación reasociar
+ un objeto con una sesión nueva. Sin embargo, la instancia separada no puede
+ haber sido modificada!
+ </para>
+
+ <programlisting><![CDATA[//just reassociate:
+sess.lock(fritz, LockMode.NONE);
+//do a version check, then reassociate:
+sess.lock(izi, LockMode.READ);
+//do a version check, using SELECT ... FOR UPDATE, then reassociate:
+sess.lock(pk, LockMode.UPGRADE);]]></programlisting>
+
+ <para>
+ Nota que <literal>lock()</literal> puede ser usado con varios <literal>LockMode</literal>s,
+ ver la documentación de la API y el capítulo sobre manejo de transacciones para más
+ información. La re-unión no es el único caso de uso para <literal>lock()</literal>.
+ </para>
+
+ <para>
+ Se discuten otros modelos para unidades de trabajo largas en <xref linkend="transactions-optimistic"/>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-saveorupdate">
+ <title>Detección automática de estado</title>
+
+ <para>
+ Los usuarios de Hibernate han pedido un método de propósito general que bien
+ salve una instancia transitoria generando un identificador nuevo, o bien
+ actualice/reúna las instancias separadas asociadas con su identificador actual.
+ El método <literal>saveOrUpdate()</literal> implementa esta funcionalidad.
+ </para>
+
+ <programlisting><![CDATA[// in the first session
+Cat cat = (Cat) firstSession.load(Cat.class, catID);
+
+// in a higher tier of the application
+Cat mate = new Cat();
+cat.setMate(mate);
+
+// later, in a new session
+secondSession.saveOrUpdate(cat); // update existing state (cat has a non-null id)
+secondSession.saveOrUpdate(mate); // save the new instance (mate has a null id)]]></programlisting>
+
+ <para>
+ El uso y semántica de <literal>saveOrUpdate()</literal> parece ser confuso para
+ usuarios nuevos. Primeramente, en tanto no estés intentando usar instancias de una
+ sesión en otra sesión nueva, no debes necesitar usar <literal>update()</literal>,
+ <literal>saveOrUpdate()</literal>, o <literal>merge()</literal>. Algunas aplicaciones
+ enteras nunca usarán ninguno de estos métodos.
+ </para>
+
+ <para>
+ Usualmente <literal>update()</literal> o <literal>saveOrUpdate()</literal> se usan en
+ el siguiente escenario:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ la aplicación carga un objeto en la primera sesión
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ el objeto es pasado a la capa de UI
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ se hacen algunas modificaciones al objeto
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ el objeto se pasa abajo de regreso a la capa de negocio
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ la aplicación hace estas modificaciones persistentes llamando
+ a <literal>update()</literal> en una segunda sesión
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ <literal>saveOrUpdate()</literal> hace lo siguiente:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ si el objeto ya es persistente en esta sesión, no hace nada
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ si otro objeto asociado con la sesión tiene el mismo identificador,
+ lanza una excepción
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ si el objeto no tiene ninguna propiedad identificadora, lo salva llamando a
+ <literal>save()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ si el identificador del objeto tiene el valor asignado a un objeto recién
+ instanciado, lo salva llamando a <literal>save()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ si el objeto está versionado (por un <literal><version></literal> o
+ <literal><timestamp></literal>), y el valor de la propiedad de versión
+ es el mismo valor asignado a una objeto recién instanciado, lo salva llamando
+ a <literal>save()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ en cualquier otro caso se actualiza el objeto llamando a <literal>update()</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ y <literal>merge()</literal> es muy diferente:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ si existe una instancia persistente con el mismo identificador asignado actualmente con la
+ sesión, copia el estado del objeto dado en la instancia persistente
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ si no existe ninguna instancia persistente actualmente asociada a la sesión,
+ intente cargarla de la base de datos, o crear una nueva instancia persistente
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ la instancia persistente es devuelta
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ la instancia dada no resulta ser asociada a la sesión, permanece separada
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect1>
+
+ <sect1 id="objectstate-deleting" revision="1">
+ <title>Borrando objetos persistentes</title>
+
+ <para>
+ <literal>Session.delete()</literal> quitará el estado de un objeto de la base de datos.
+ Por supuesto, tu aplicación podría tener aún una referencia a un objeto borrado. Lo mejor
+ es pensar en <literal>delete()</literal> como hacer transitoria una instancia persistente.
+ </para>
+
+ <programlisting><![CDATA[sess.delete(cat);]]></programlisting>
+
+ <para>
+ Puedes borrar los objetos en el orden que gustes, sin riesgo de violaciones
+ de restricción de clave foránea. Aún es posible violar una restricción
+ <literal>NOT NULL</literal> sobre una columna clave foránea borrando objetos
+ en un orden erróneo, por ejemplo, si borras el padre, pero olvidas borrar los
+ hijos.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-replicating" revision="1">
+ <title>Replicando objetos entre dos almacénes de datos diferentes</title>
+
+ <para>
+ Es ocasionalmente útil ser capaz de tomar un grafo de instancias persistentes
+ y hacerlas persistentes en un almacén de datos diferente, sin regenerar los valores
+ identificadores.
+ </para>
+
+ <programlisting><![CDATA[//retrieve a cat from one database
+Session session1 = factory1.openSession();
+Transaction tx1 = session1.beginTransaction();
+Cat cat = session1.get(Cat.class, catId);
+tx1.commit();
+session1.close();
+
+//reconcile with a second database
+Session session2 = factory2.openSession();
+Transaction tx2 = session2.beginTransaction();
+session2.replicate(cat, ReplicationMode.LATEST_VERSION);
+tx2.commit();
+session2.close();]]></programlisting>
+
+ <para>
+ El <literal>ReplicationMode</literal> determina cómo <literal>replicate()</literal>
+ tratará los conflictos con filas existentes en la base de datos.
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>ReplicationMode.IGNORE</literal> - ignora el objeto cuando existe una fila
+ de base de datos con el mismo identificador
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>ReplicationMode.OVERWRITE</literal> - sobrescribe cualquier fila de base de
+ datos existente con el mismo identificador
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>ReplicationMode.EXCEPTION</literal> - lanza una excepción si existe una fila
+ de base de datos con el mismo identificador
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>ReplicationMode.LATEST_VERSION</literal> - sobrescribe la fila si su número
+ de versión es anterior al número de versión del objeto, o en caso contrario ignora el objeto
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Los casos de uso para esta funcionalidad incluyen reconciliar datos ingresados en
+ instancias diferentes de bases de datos, actualizar información de configuración de
+ sistema durante actualizaciones de producto, deshacer cambios producidos durante
+ transacciones no-ACID y más.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-flushing">
+ <title>Limpiando (flushing) la sesión</title>
+
+ <para>
+ Cada tanto, la <literal>Session</literal> ejecutará las sentencias SQL necesarias para
+ sincronizar el estado de la conexión JDBC con el estado de los objetos mantenidos en menoria.
+ Este proceso, <emphasis>limpieza (flush)</emphasis>, ocurre por defecto en los siguientes
+ puntos
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ antes de algunas ejecuciones de consulta
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ desde <literal>org.hibernate.Transaction.commit()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ desde <literal>Session.flush()</literal>
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Las sentencias SQL son liberadas en el siguiente orden
+ </para>
+
+ <orderedlist spacing="compact">
+ <listitem>
+ <para>
+ todas las inserciones de entidades, en el mismo orden que los objetos
+ correspondientes fueron salvados usando <literal>Session.save()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ todas las actualizaciones de entidades
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ todas los borrados de colecciones
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ todos los borrados, actualizaciones e inserciones de elementos de colección
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ todas las inserciones de colecciones
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ todos los borrados de entidades, en el mismo orden que los objetos
+ correspondientes fueron borrados usando <literal>Session.delete()</literal>
+ </para>
+ </listitem>
+ </orderedlist>
+
+ <para>
+ (Una excepción es que los objetos que usan generación de ID <literal>native</literal>
+ se insertan cuando son salvados.)
+ </para>
+
+ <para>
+ Excepto cuando llamas explícitamente a <literal>flush()</literal>, no hay en absoluto
+ garantías sobre <emphasis>cuándo</emphasis> la <literal>Session</literal> ejecuta las
+ llamadas JDBC. sólo sobre el <emphasis>orden</emphasis> en que son ejecutadas. Sin embargo,
+ Hibernate garantiza que los métodos <literal>Query.list(..)</literal> nunca devolverán datos
+ añejos o erróneos.
+ </para>
+
+ <para>
+ Es posible cambiar el comportamiento por defecto de modo que la limpieza (flush)
+ ocurra menos frecuentemente. La clase <literal>FlushMode</literal> tres modos
+ diferentes: sólo en tiempo de compromiso (y sólo cuando se use la API de
+ <literal>Transaction</literal> de Hibernate), limpieza automática usando la rutina
+ explicada, o nunca limpiar a menos que se llame a <literal>flush()</literal>
+ explícitamente. El último modo es útil para unidades de trabajo largas, donde una
+ <literal>Session</literal> se mantiene abierta y desconectada por largo tiempo
+ (ver <xref linkend="transactions-optimistic-longsession"/>).
+ </para>
+
+ <programlisting><![CDATA[sess = sf.openSession();
+Transaction tx = sess.beginTransaction();
+sess.setFlushMode(FlushMode.COMMIT); // allow queries to return stale state
+
+Cat izi = (Cat) sess.load(Cat.class, id);
+izi.setName(iznizi);
+
+// might return stale data
+sess.find("from Cat as cat left outer join cat.kittens kitten");
+
+// change to izi is not flushed!
+...
+tx.commit(); // flush occurs]]></programlisting>
+
+ <para>
+ Durante la limpieza, puede ocurrir una excepción (por ejemplo, si una operación DML
+ violase una restricción). Ya que el manejo de excepciones implica alguna comprensión
+ del comportamiento transaccional de Hibernate, lo discutimos en <xref linkend="transactions"/>.
+ </para>
+
+ </sect1>
+
+ <sect1 id="objectstate-transitive">
+ <title>Persistencia transitiva</title>
+
+ <para>
+ Es absolutamente incómodo dalvar, borrar, o reunir objetos individuales,
+ especialmente si tratas con un grafo de objetos asociados. Un caso común es
+ una relación padre/hijo. Considera el siguiente ejemplo:
+ </para>
+
+ <para>
+ Si los hijos en una relación padre/hijo pudieran ser tipificados en valor
+ (por ejemplo, una colección de direcciones o cadenas), sus ciclos de vida
+ dependerían del padre y se requeriría ninguna otra acción para el tratamiento
+ en "cascada" de cambios de estado. Cuando el padre es salvado, los objetos hijo
+ tipificados en valor son salvados también, cuando se borra el padre, se borran
+ los hijos, etc. Esto funciona incluso para operaciones como el retiro de un
+ hijo de la colección. Hibernate detectará esto y, ya que los objetos tipificados
+ en valor no pueden tener referencias compartidas, borrará el hijo de la base
+ de datos.
+ </para>
+
+ <para>
+ Ahora considera el mismo escenario con los objetos padre e hijos siendo entidades,
+ no tipos de valor (por ejemplo, categorías e ítems, o gatos padre e hijos).
+ Las entidades tienen su propio ciclo de vida, soportan referencias compartidas
+ (de modo que quitar una entidad de una colección no significa que sea borrada),
+ y no hay por defecto ningún tratamiento en "cascada" de estado de una entidad
+ a otras entidades asociadas. Hibernate no implementa <emphasis>persistencia por
+ alcance</emphasis>.
+ </para>
+
+ <para>
+ Para cada operación básica de la sesión de Hibernate - incluyendo <literal>persist(), merge(),
+ saveOrUpdate(), delete(), lock(), refresh(), evict(), replicate()</literal> - hay un estilo
+ de cascada correspondiente. Respectivamente, los estilos de cascada se llaman <literal>create,
+ merge, save-update, delete, lock, refresh, evict, replicate</literal>. Si quieres que una
+ operación sea tratada en cascada a lo largo de una asociación, debes indicar eso en el
+ documento de mapeo. Por ejemplo:
+ </para>
+
+ <programlisting><![CDATA[<one-to-one name="person" cascade="persist"/>]]></programlisting>
+
+ <para>
+ Los estilos de cascada pueden combinarse:
+ </para>
+
+ <programlisting><![CDATA[<one-to-one name="person" cascade="persist,delete,lock"/>]]></programlisting>
+
+ <para>
+ Puedes incluso usar <literal>cascade="all"</literal> para especificar que <emphasis>todas</emphasis>
+ las operaciones deben ser tratadas en cascada a lo largo de la asociación. El por defecto
+ <literal>cascade="none"</literal> especifica que ninguna operación será tratada en cascada.
+ </para>
+
+ <para>
+ Un estilo de cascada especial, <literal>delete-orphan</literal>, se aplica sólo a
+ asociaciones uno-a-muchos, e indica que la operación <literal>delete()</literal> debe
+ aplicarse a cualquier objeto hijo que sea quitado de la asociación.
+ </para>
+
+
+ <para>
+ Recomendaciones:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Usualmente no tiene sentido habilitar el tratamiento en cascada a una asociación
+ <literal><many-to-one></literal> o <literal><many-to-many></literal>.
+ El tratamiento en cascada es frecuentemente útil para las asociaciones
+ <literal><one-to-one></literal> y <literal><one-to-many></literal>.
+ associations.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Si la esperanza de vida de los objetos hijos está ligada a la eesperanza de
+ vida del objeto padre, házlo un <emphasis>objeto de ciclo de vida</emphasis>
+ especificando <literal>cascade="all,delete-orphan"</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ En otro caso, puede que no necesites tratamiento en cascada en absoluto. Pero
+ si piensas que estarás trabajando frecuentemente con padre e hijos juntos en la
+ misma transacción, y quieres ahorrarte algo de tipeo, considera usar
+ <literal>cascade="persist,merge,save-update"</literal>.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Mapear una asociación (ya sea una asociación monovaluada, o una colección) con
+ <literal>cascade="all"</literal> marca la asociación como una relación del estilo
+ <emphasis>padre/hijo</emphasis> donde save/update/delete en el padre resulta
+ en save/update/delete del hijo o hijos.
+ </para>
+ <para>
+ Además, una mera referencia a un hijo desde un padre persistente resultará en
+ un save/update del hijo. Esta metáfora está incompleta, sin embargo. Un hijo
+ que deje de ser referenciado por su padre <emphasis>no</emphasis> es borrado
+ automáticamente, excepto en el caso de una asociación <literal><one-to-many></literal>
+ mapeada con <literal>cascade="delete-orphan"</literal>. La semántica precisa de
+ las operaciones en cascada para una relación padre/hijo es:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Si un padre le es pasado a <literal>persist()</literal>, todos los hijos le son
+ pasados a <literal>persist()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Si un padre le es pasado a <literal>merge()</literal>, todos los hijos le son
+ pasados a <literal>merge()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Si un padre le es pasado a <literal>save()</literal>, <literal>update()</literal> o
+ <literal>saveOrUpdate()</literal>, todos los hijos le son pasados a <literal>saveOrUpdate()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Si un hijo transitorio o separado se vuelve referenciado por un padre
+ persistente, le es pasado a <literal>saveOrUpdate()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Si un padre es borrado, todos los hijos le son pasados a <literal>delete()</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Si un hijo deja de ser referenciado por un padre persistente,
+ <emphasis>no ocurre nada especial</emphasis> - la aplicación debe
+ borrar explícitamente el hijo de ser necesario - a menos que
+ <literal>cascade="delete-orphan"</literal>, en cuyo caso el hijo
+ "huérfano" es borrado.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect1>
+
+ <sect1 id="objectstate-metadata">
+ <title>Usando metadatos</title>
+
+ <para>
+ Hibernate requiere de un modelo de meta-nivel muy rico de todas las entidades y tipos de valor.
+ De vez en cuando, este modelo es muy útil para la aplicación misma. Por ejemplo, la aplicación
+ podría usar los metadatos de Hibernate para implementar un algoritmo "inteligente" de copia
+ en profundidad que entienda qué objetos deben ser copiados (por ejemplo, tipo de valor mutables)
+ y cuáles no (por ejemplo, tipos de valor inmutables y, posiblemente, entidades asociadas).
+ </para>
+ <para>
+ Hibernate expone los metadatos vía las interfaces <literal>ClassMetadata</literal> y
+ <literal>CollectionMetadata</literal> y la jerarquía <literal>Type</literal>. Las instancias
+ de las interfaces de metadatos pueden obtenerse de <literal>SessionFactory</literal>.
+ </para>
+
+ <programlisting><![CDATA[Cat fritz = ......;
+ClassMetadata catMeta = sessionfactory.getClassMetadata(Cat.class);
+
+Object[] propertyValues = catMeta.getPropertyValues(fritz);
+String[] propertyNames = catMeta.getPropertyNames();
+Type[] propertyTypes = catMeta.getPropertyTypes();
+
+// get a Map of all properties which are not collections or associations
+Map namedValues = new HashMap();
+for ( int i=0; i<propertyNames.length; i++ ) {
+ if ( !propertyTypes[i].isEntityType() && !propertyTypes[i].isCollectionType() ) {
+ namedValues.put( propertyNames[i], propertyValues[i] );
+ }
+}]]></programlisting>
+
+ </sect1>
+
+</chapter>
+
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/content/toolset_guide.xml (from rev 12794, core/trunk/documentation/manual/es-ES/src/main/docbook/modules/toolset_guide.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/toolset_guide.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/toolset_guide.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,459 @@
+<chapter id="toolsetguide" revision="2">
+ <title>Guía del Conjunto de Herramientas</title>
+
+ <para>
+ La ingeniería de ida y vuelta con Hibernate es posible usando un conjunto de plugins de Eclipse,
+ herramientas de línea de comandos, así como tareas de Ant.
+ </para>
+
+ <para>
+ Las <emphasis>Herramientas de Hibernate</emphasis> actualmente incluyen plugins para la IDE de
+ Eclipse así como tareas de Ant para la ingeniería inversa de bases de datos existentes:
+ </para>
+
+ <itemizedlist>
+ <listitem><para>
+ <emphasis>Editor de Mapeo:</emphasis> Un editor de ficheros de mapeo XML, que soporta autocompleción
+ y resaltado de sintáxis. Soporta también autocompleción semántica de nombres de clases y nombres de
+ campos/propiedades, haciéndolo mucho más versátil que un editor de XML normal.
+ </para></listitem>
+ <listitem><para>
+ <emphasis>Consola:</emphasis> La consola es una nueva vista en Eclipse. Además de la vista de
+ árbol de tus configuraciones de consola, tienes también una vista interactiva de tus clases
+ persistentes y sus relaciones. La console te permite ejecutar consultas HQL contra tu base de datos y
+ navegar el resultado directamente en Eclipse.
+ </para></listitem>
+ <listitem><para>
+ <emphasis>Asistentes de Desarrollo:</emphasis> Se proveen muchos asistentes con las herramientas
+ de Eclipse. Puedes usar un asistente para generar rápidamente ficheros de configuración de Hibernate
+ (cfg.xml), o incluso puedes haceruna ingeniería inversa completa de un esquema de base de datos existente
+ en ficheros de código de POJO y ficheros de mapeo de Hibernate. El asistente de ingeniería inversa soporta
+ plantillas personalizables.
+ </para></listitem>
+ <listitem><para>
+ <emphasis>Tareas de Ant:</emphasis>
+ </para></listitem>
+
+ </itemizedlist>
+
+ <para>
+ Por favor refiérete al paquete <emphasis>Herramientas de Hibernate</emphasis> y su documentación para
+ más información.
+ </para>
+
+ <para>
+ Sin embargo, el paquete principal de Hibernate viene incluyendo una herramienta integrada
+ (puede ser usada incluso "dentro" de Hibernate on-the-fly): <emphasis>SchemaExport</emphasis>
+ también conocido como <literal>hbm2ddl</literal>.
+ </para>
+
+ <sect1 id="toolsetguide-s1" revision="2">
+ <title>Generación automática de esquemas</title>
+
+ <para>
+ Una utilidad de Hibernate puede generar DDL desde tus ficheros de mapeo. El esquema generado incluye
+ restricciones de integridad referencial (claves primarias y foráneas) para las tablas de entidades y
+ colecciones. Las tablas y secuencias también son creadas para los generadores de identificadores mapeados.
+ </para>
+
+ <para>
+ <emphasis>Debes</emphasis> especificar un <literal>Dialecto</literal> SQL vía la propiedad
+ <literal>hibernate.dialect</literal> al usar esta herramienta, ya que el DDL es altamente específico del
+ vendedor.
+ </para>
+
+ <para>
+ First, customize your mapping files to improve the generated schema.
+ </para>
+
+ <sect2 id="toolsetguide-s1-2" revision="1">
+ <title>Personalizando el esquema</title>
+
+ <para>
+ Muchos elementos de mapeo de Hibernate definen un atributo opcional llamado <literal>length</literal>.
+ Con este atributo puedes establecer el tamaño de una columna. (O, para tipos de datos
+ numéricos/decimales, la precisión.)
+ </para>
+
+ <para>
+ Algunas etiquetas también aceptan un atributo <literal>not-null</literal> (para generar una restricción
+ <literal>NOT NULL</literal> en columnas de tablas) y y un atributo <literal>unique</literal> (para generar
+ restricciones <literal>UNIQUE</literal> en columnas de tablas).
+ </para>
+
+ <para>
+ Algunas etiquetas aceptan un atributo <literal>index</literal> para especificar el nombre de un índice
+ para esa columna. Se puede usar un atributo <literal>unique-key</literal> para agrupar columnas en una
+ restricción de clave de una sola unidad. Actualmente, el valor especificado del atributo
+ <literal>unique-key</literal> <emphasis>no</emphasis> es usado para nombrar la restricción, sólo para
+ agrupar las columnas en el fichero de mapeo.
+ </para>
+
+ <para>
+ Ejemplos:
+ </para>
+
+ <programlisting><![CDATA[<property name="foo" type="string" length="64" not-null="true"/>
+
+<many-to-one name="bar" foreign-key="fk_foo_bar" not-null="true"/>
+
+<element column="serial_number" type="long" not-null="true" unique="true"/>]]></programlisting>
+
+ <para>
+ Alternativamente, estos elementos aceptan tambíen un elemento hijo <literal><column></literal>.
+ Esto es particularmente útil para tipos multicolumnas:
+ </para>
+
+ <programlisting><![CDATA[<property name="foo" type="string">
+ <column name="foo" length="64" not-null="true" sql-type="text"/>
+</property>]]></programlisting>
+
+ <programlisting><![CDATA[<property name="bar" type="my.customtypes.MultiColumnType"/>
+ <column name="fee" not-null="true" index="bar_idx"/>
+ <column name="fi" not-null="true" index="bar_idx"/>
+ <column name="fo" not-null="true" index="bar_idx"/>
+</property>]]></programlisting>
+
+ <para>
+ El atributo <literal>sql-type</literal> permite al usuario sobrescribir el mapeo por defecto de
+ tipo Hibernate a tipo de datos SQL.
+ </para>
+
+ <para>
+ El atributo <literal>check</literal> te permite especificar una comprobación de restricción.
+ </para>
+
+ <programlisting><![CDATA[<property name="foo" type="integer">
+ <column name="foo" check="foo > 10"/>
+</property>]]></programlisting>
+
+ <programlisting><![CDATA[<class name="Foo" table="foos" check="bar < 100.0">
+ ...
+ <property name="bar" type="float"/>
+</class>]]></programlisting>
+
+
+ <table frame="topbot" id="schemattributes-summary" revision="2">
+ <title>Resumen</title>
+ <tgroup cols="3">
+ <colspec colwidth="1*"/>
+ <colspec colwidth="1*"/>
+ <colspec colwidth="2.5*"/>
+ <thead>
+ <row>
+ <entry>Atributo</entry>
+ <entry>Valores</entry>
+ <entry>Interpretación</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>length</literal></entry>
+ <entry>number</entry>
+ <entry>largo de columna/precisión decimal</entry>
+ </row>
+ <row>
+ <entry><literal>not-null</literal></entry>
+ <entry><literal>true|false</literal></entry>
+ <entry>especifica que la columna debe ser no nulable</entry>
+ </row>
+ <row>
+ <entry><literal>unique</literal></entry>
+ <entry><literal>true|false</literal></entry>
+ <entry>especifica que la columna debe tener una restricción de unicidad</entry>
+ </row>
+ <row>
+ <entry><literal>index</literal></entry>
+ <entry><literal>index_name</literal></entry>
+ <entry>especifica el nombre de un índice (multicolumna)</entry>
+ </row>
+ <row>
+ <entry><literal>unique-key</literal></entry>
+ <entry><literal>unique_key_name</literal></entry>
+ <entry>especifica el nombre de una restricción de unicidad multicolumna</entry>
+ </row>
+ <row>
+ <entry><literal>foreign-key</literal></entry>
+ <entry><literal>foreign_key_name</literal></entry>
+ <entry>
+ especifica el nombre de la restricción de clave foránea generada por una
+ asociación, úsalo en los elementos de mapeo <one-to-one>, <many-to-one>,
+ <key>, y <many-to-many>. Nota que los lados
+ <literal>inverse="true"</literal> no serán considerados por
+ <literal>SchemaExport</literal>.
+ </entry>
+ </row>
+ <row>
+ <entry><literal>sql-type</literal></entry>
+ <entry><literal>column_type</literal></entry>
+ <entry>
+ sobrescribe el tipo de columna por defecto (sólo atributo del elemento
+ <literal><column></literal>)
+ </entry>
+ </row>
+ <row>
+ <entry><literal>check</literal></entry>
+ <entry>expresión SQL</entry>
+ <entry>
+ crea una restricción de comprobación SQL en columna o tabla
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ El elemento <literal><comment></literal> te permite especificar un comentario para el esquema
+ generado.
+ </para>
+
+ <programlisting><![CDATA[<class name="Customer" table="CurCust">
+ <comment>Current customers only</comment>
+ ...
+</class>]]></programlisting>
+
+ <programlisting><![CDATA[<property name="balance">
+ <column name="bal">
+ <comment>Balance in USD</comment>
+ </column>
+</property>]]></programlisting>
+
+ <para>
+ Esto resulta en una sentencia <literal>comment on table</literal> o <literal>comment on column</literal>
+ en el DDL generado (donde esté soportado).
+ </para>
+
+ </sect2>
+
+ <sect2 id="toolsetguide-s1-3">
+ <title>Ejecutando la herramienta</title>
+
+ <para>
+ La herramienta <literal>SchemaExport</literal> escribe un guión DDL a la salida estándar y/o
+ ejecuta las sentencias DDL.
+ </para>
+
+ <para>
+ <literal>java -cp </literal><emphasis>classpaths_de_hibernate</emphasis>
+ <literal>org.hibernate.tool.hbm2ddl.SchemaExport</literal> <emphasis>opciones ficheros_de_mapeo</emphasis>
+ </para>
+
+ <table frame="topbot">
+ <title>Opciones de Línea de Comandos de <literal>SchemaExport</literal></title>
+ <tgroup cols="2">
+ <colspec colwidth="1.5*"/>
+ <colspec colwidth="2*"/>
+ <thead>
+ <row>
+ <entry>Opción</entry>
+ <entry>Descripción</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>--quiet</literal></entry>
+ <entry>no enviar a salida estándar el guión</entry>
+ </row>
+ <row>
+ <entry><literal>--drop</literal></entry>
+ <entry>sólo desechar las tablas</entry>
+ </row>
+ <row>
+ <entry><literal>--text</literal></entry>
+ <entry>no exportar a la base de datos</entry>
+ </row>
+ <row>
+ <entry><literal>--output=my_schema.ddl</literal></entry>
+ <entry>enviar la salida del guión ddl a un fichero</entry>
+ </row>
+ <row>
+ <entry><literal>--config=hibernate.cfg.xml</literal></entry>
+ <entry>lee la configuración de Hibernate de un fichero XML</entry>
+ </row>
+ <row>
+ <entry><literal>--properties=hibernate.properties</literal></entry>
+ <entry>lee las propiedades de base de datos de un fichero</entry>
+ </row>
+ <row>
+ <entry><literal>--format</literal></entry>
+ <entry>formatea agradablemente el SQL generado en el guión</entry>
+ </row>
+ <row>
+ <entry><literal>--delimiter=x</literal></entry>
+ <entry>establece un delimitador de fin de línea para el guión</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ Puedes incluso encajar <literal>SchemaExport</literal> en tu aplicación:
+ </para>
+
+ <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaExport(cfg).create(false, true);]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="toolsetguide-s1-4">
+ <title>Propiedades</title>
+
+ <para>
+ Las propiedades de base de datos pueden especificarse
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>como propiedades de sistema con <literal>-D</literal><emphasis><property></emphasis></para>
+ </listitem>
+ <listitem>
+ <para>en <literal>hibernate.properties</literal></para>
+ </listitem>
+ <listitem>
+ <para>en un fichero de propiedades mencionado con <literal>--properties</literal></para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Las propiedades necesarias son:
+ </para>
+
+ <table frame="topbot">
+ <title>Propiedades de Conexión de SchemaExport</title>
+ <tgroup cols="2">
+ <colspec colwidth="1.5*"/>
+ <colspec colwidth="2*"/>
+ <thead>
+ <row>
+ <entry>Nombre de Propiedad</entry>
+ <entry>Descripción</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>hibernate.connection.driver_class</literal></entry>
+ <entry>clase del driver jdbc</entry>
+ </row>
+ <row>
+ <entry><literal>hibernate.connection.url</literal></entry>
+ <entry>url de jdbc</entry>
+ </row>
+ <row>
+ <entry><literal>hibernate.connection.username</literal></entry>
+ <entry>usuario de base de datos</entry>
+ </row>
+ <row>
+ <entry><literal>hibernate.connection.password</literal></entry>
+ <entry>contraseña de usuario</entry>
+ </row>
+ <row>
+ <entry><literal>hibernate.dialect</literal></entry>
+ <entry>dialecto</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </sect2>
+
+ <sect2 id="toolsetguide-s1-5">
+ <title>Usando Ant</title>
+
+ <para>
+ Puedes llamar a <literal>SchemaExport</literal> desde tu guión de construcción de Ant:
+ </para>
+
+ <programlisting><![CDATA[<target name="schemaexport">
+ <taskdef name="schemaexport"
+ classname="org.hibernate.tool.hbm2ddl.SchemaExportTask"
+ classpathref="class.path"/>
+
+ <schemaexport
+ properties="hibernate.properties"
+ quiet="no"
+ text="no"
+ drop="no"
+ delimiter=";"
+ output="schema-export.sql">
+ <fileset dir="src">
+ <include name="**/*.hbm.xml"/>
+ </fileset>
+ </schemaexport>
+</target>]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="toolsetguide-s1-6">
+ <title>Actualizaciones incrementales de esquema</title>
+
+ <para>
+ La herramienta <literal>SchemaUpdate</literal> actualizará un esquema existente con cambios
+ "incrementales". Nota que <literal>SchemaUpdate</literal> depende fuertemente de la API de metadatos
+ de JDBC, de modo que no funcionará con todos los drivers JDBC.
+ </para>
+
+ <para>
+ <literal>java -cp </literal><emphasis>classpaths_de_hibernate</emphasis>
+ <literal>org.hibernate.tool.hbm2ddl.SchemaUpdate</literal> <emphasis>opciones ficheros_de_mapeo</emphasis>
+ </para>
+
+ <table frame="topbot">
+ <title>Opciones de Línea de Comandos de <literal>SchemaUpdate</literal></title>
+ <tgroup cols="2">
+ <colspec colwidth="1.5*"/>
+ <colspec colwidth="2*"/>
+ <thead>
+ <row>
+ <entry>Opción</entry>
+ <entry>Descripción</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>--quiet</literal></entry>
+ <entry>no enviar a salida estándar el guión</entry>
+ </row>
+ <row>
+ <entry><literal>--properties=hibernate.properties</literal></entry>
+ <entry>lee las propiedades de base de datos de un fichero</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <para>
+ Puedes encajar <literal>SchemaUpdate</literal> en tu aplicación:
+ </para>
+
+ <programlisting><![CDATA[Configuration cfg = ....;
+new SchemaUpdate(cfg).execute(false);]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="toolsetguide-s1-7">
+ <title>Usando Ant para actualizaciones incrementales de esquema</title>
+
+ <para>
+ Puedes llamar a <literal>SchemaUpdate</literal> desde el guión de Ant:
+ </para>
+
+ <programlisting><![CDATA[<target name="schemaupdate">
+ <taskdef name="schemaupdate"
+ classname="org.hibernate.tool.hbm2ddl.SchemaUpdateTask"
+ classpathref="class.path"/>
+
+ <schemaupdate
+ properties="hibernate.properties"
+ quiet="no">
+ <fileset dir="src">
+ <include name="**/*.hbm.xml"/>
+ </fileset>
+ </schemaupdate>
+</target>]]></programlisting>
+
+ </sect2>
+
+ </sect1>
+
+</chapter>
+
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/content/transactions.xml (from rev 12794, core/trunk/documentation/manual/es-ES/src/main/docbook/modules/transactions.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/transactions.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/transactions.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,925 @@
+<chapter id="transactions" revision="1">
+ <title>Transacciones y Concurrencia</title>
+
+ <para>
+ El punto más importante sobre Hibernate y el control de concurrencia es que muy fácil
+ de comprender. Hibernate usa directamente conexiones JDBC y recursos JTA sin agregar
+ ningún comportamiento de bloqueo adicional. Recomendamos altamente que gastes algo de
+ tiempo con la especificación de JDBC, ANSI, y el aislamiento de transacciones de tu sistema
+ de gestión de base de datos. Hibernate sólo añade versionado automático pero no bloquea
+ objetos en memoria ni cambia el nivel de aislamiento de tus transacciones de base de datos.
+ Básicamente, usa Hibernate como usarías JDBC directo (o JTA/CMT) con tus recursos de base de
+ datos.
+ </para>
+
+ <para>
+ Sin embargo, además del versionado automático, Hibernate ofrece una API (menor) para
+ bloqueo pesimista de filas, usando la sintáxis <literal>SELECT FOR UPDATE</literal>.
+ Esta API se discute más adelante en este capítulo:
+ </para>
+
+ <para>
+ Comenzamos la discusión del control de concurrencia en Hibernate con la granularidad
+ de <literal>Configuration</literal>, <literal>SessionFactory</literal>, y
+ <literal>Session</literal>, así como la base de datos y las transacciones de aplicación
+ largas.
+ </para>
+
+ <sect1 id="transactions-basics">
+ <title>Ámbitos de sesión y de transacción</title>
+
+ <para>
+ Una <literal>SessionFactory</literal> es un objeto seguro entre hebras caro-de-crear
+ pensado para ser compartido por todas las hebras de la aplicación. Es creado una sola vez,
+ usualmente en el arranque de la aplicación, a partir de una instancia de <literal>Configuration</literal>.
+ </para>
+
+ <para>
+ Una <literal>Session</literal> es un objeto barato, inseguro entre hebras que debe
+ ser usado una sola vez, para un solo proceso de negocio, una sola unidad de trabajo,
+ y luego descartado. Una <literal>Session</literal> no obtendrá una <literal>Connection</literal>
+ JDBC (o un <literal>Datasource</literal>) a menos que sea necesario, de modo que puedas
+ abrir y cerrar seguramente una <literal>Session</literal> incluso si no estás seguro
+ que se necesitará acceso a los datos para servir una petición en particular. (Esto se
+ vuelve importante en cuanto estés implementando alguno de los siguientes patrones usando
+ intercepción de peticiones).
+ </para>
+
+ <para>
+ Para completar este cuadro tienes que pensar también en las transacciones de base de
+ datos. Una transacción de base de datos tiene que ser tan corta como sea posible, para
+ reducir la contención de bloqueos en la base de datos. Las transacciones largas de base de
+ datos prevendrán a tu aplicación de escalar a una carga altamente concurrente.
+ </para>
+
+ <para>
+ ¿Qué es el ámbito de una unidad de trabajo? ¿Puede una sola <literal>Session</literal> de Hibernate
+ extenderse a través de varias transacciones de base de datos o es ésta una relación uno-a-uno
+ de ámbitos? ¿Cuándo debes abrir y cerrar una <literal>Session</literal> y cómo demarcas los
+ límites de la transacción de base de datos?
+ </para>
+
+ <sect2 id="transactions-basics-uow">
+ <title>Unidad de trabajo</title>
+
+ <para>
+ Primero, no uses el antipatrón <emphasis>sesión-por-operación</emphasis>, esto es,
+ ¡no abras y cierres una <literal>Session</literal> para cada simple llamada a la base
+ de datos en una sola hebra! Por supuesto, lo mismo es verdad para transacciones de base de
+ datos. Las llamadas a base de datos en una aplicación se hacen usando una secuencia
+ prevista, que están agrupadas dentro de unidades de trabajo atómicas. (Nota que esto
+ también significa que el auto-commit después de cada una de las sentencias SQL es inútil
+ en una aplicación, este modo está pensado para trabajo ad-hoc de consola SQL.
+ Hibernate deshabilita, o espera que el servidor de aplicaciones lo haga, el modo
+ auto-commit inmediatamente.)
+ </para>
+
+ <para>
+ El patrón más común en una aplicación mutiusuario cliente/servidor es
+ <emphasis>sesión-por-petición</emphasis>. En este modelo, una petición del cliente
+ es enviada al servidor (en donde se ejecuta la capa de persistencia de Hibernate),
+ se abre una nueva <literal>Session</literal> de Hibernate, y todas las operaciones
+ de base de datos se ejecutan en esta unidad de trabajo. Una vez completado el trabajo
+ (y se ha preparado la respuesta para el cliente) la sesión es limpiada y cerrada.
+ Podrías usar una sola transacción de base de datos para servir a petición del cliente,
+ comenzándola y comprometiéndola cuando abres y cierras la <literal>Session</literal>.
+ La relación entre las dos es uno-a-uno y este modelo es a la medida perfecta de muchas
+ aplicaciones.
+ </para>
+
+ <para>
+ El desafío yace en la implementación: no sólo tienen que comenzarse y terminarse correctamente
+ la <literal>Session</literal> y la transacción, sino que además tienen que estar accesibles
+ para las operaciones de acceso a datos. La demarcación de una unidad de trabajo se implementa
+ idealmente usando un interceptor que se ejecuta cuando una petición llama al servidor y anter que
+ la respuesta sea enviada (es decir, un <literal>ServletFilter</literal>). Recomendamos ligar la
+ <literal>Session</literal> a la hebra que atiende la petición, usando una variable
+ <literal>ThreadLocal</literal>. Esto permite un fácil acceso (como acceder a una variable static)
+ en tódo el código que se ejecuta en esta hebra. Dependiendo del mecanismo de demarcación de
+ transacciones de base de datos que elijas, podrías mantener también el contexto de la transacción
+ en una variable <literal>ThreadLocal</literal>. Los patrones de implementación para esto son
+ conocidos como <emphasis>Sesión Local de Hebra (ThreadLocal Session)</emphasis> y
+ <emphasis>Sesión Abierta en Vista (Open Session in View)</emphasis>. Puedes extender fácilmente
+ la clase de ayuda <literal>HibernateUtil</literal> mostrada anteriormente para encontrar
+ una forma de implementar un interceptor e instalarlo en tu entorno. Ver el sitio web de Hibernate
+ para consejos y ejemplos.
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-basics-apptx">
+ <title>Transacciones de aplicación</title>
+
+ <para>
+ El patrón sesión-por-petición no es el único concepto útil que puedes usar para diseñar unidades
+ de trabajo. Muchos procesos de negocio requiere una serie completa de interacciones con el
+ usuario intercaladas con accesos a base de datos. En aplicaciones web y de empresa no es aceptable
+ que una transacción de base de datos se extienda a través de la interacción de un usuario.
+ Considera el siguiente ejemplo:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ Se abre la primera pantalla de un diálogo, los datos vistos por el usuario han sido
+ cargados en una <literal>Session</literal> y transacción de base de datos particular.
+ El usuario es libre de modificar los objetos.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ El usuario hace click en "Salvar" después de 5 minutos y espera que sus modificaciones
+ sean hechas persistentes. También espera que él sea la única persona editando esta
+ información y que no puede ocurrir ninguna modificación en conflicto.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Llamamos a esto unidad de trabajo, desde el punto de vista del usuario, una larga
+ <emphasis>transacción de aplicación</emphasis> ejecutándose. Hay muchas formas en
+ que puedes implementar esto en tu aplicación.
+ </para>
+
+ <para>
+ Una primera implementación ingenua podría mantener abierta la <literal>Session</literal>
+ y la transacción de base de datos durante el tiempo de pensar del usuario, con bloqueos
+ tomados en la base de datos para prevenir la modificación concurrente, y para garantizar
+ aislamiento y atomicidad. Esto es, por supuesto, un antipatrón, ya que la contención de
+ bloqueo no permitiría a la aplicación escalar con el número de usuarios concurrentes.
+ </para>
+
+ <para>
+ Claramente, tenemos que usar muchas transacciones de base de datos para implementar la transacción
+ de aplicación. En este caso, mantener el aislamiento de los procesos de negocio se vuelve una
+ responsabilidad parcial de la capa de aplicación. Una sola transacción de aplicación usualmente
+ abarca varias transacciones de base de datos. Será atómica si sólo una de estas transacciones de
+ base de datos (la última) almacena los datos actualizados, todas las otras simplemente leen datos
+ (por ejemplo, en un diálogo estilo-asistente abarcando muchos ciclos petición/respuesta).
+ Esto es más fácil de implementar de lo que suena, especialmente si usas las funcionalidades de
+ Hibernate:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ <emphasis>Versionado Automático</emphasis> - Hibernate puede llevar un control automático de
+ concurrencia optimista por ti, puede detectar automáticamente si una modificación concurrente
+ ha ocurrido durante el tiempo de pensar del usuario.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Objetos Separados</emphasis> - Si decides usar el ya discutido patrón
+ de <emphasis>sesión-por-petición</emphasis>, todas las instancias cargadas estarán
+ en estado separado durante el tiempo de pensar del usuario. Hibernate te permite
+ volver a unir los objetos y hacer persistentes las modificaciones. El patrón se
+ llama <emphasis>sesión-por-petición-con-objetos-separados</emphasis>. Se usa
+ versionado automático para aislar las modificaciones concurrentes.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Sesión Larga</emphasis> - La <literal>Session</literal> de Hibernate puede ser
+ desconectada de la conexión JDBC subyacente después que se haya sido comprometida la
+ transacción de base de datos, y reconectada cuando ocurra una nueva petición del cliente.
+ Este patrón es conocido como <emphasis>sesión-por-transacción-de-aplicación</emphasis>
+ y hace la re-unión innecesaria. Para aislar las modificaciones concurrentes se usa el
+ versionado automático.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Tanto <emphasis>sesión-por-petición-con-objetos-separados</emphasis> como
+ <emphasis>sesión-por-transacción-de-aplicación</emphasis>, ambas tienen
+ ventajas y desventajas, las discutimos más adelante en este capítulo en el contexto
+ del control optimista de concurrencia.
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-basics-identity">
+ <title>Considerando la identidad del objeto</title>
+
+ <para>
+ Una aplicación puede acceder concurrentemente a el mismo estado persistente en dos
+ <literal>Session</literal>s diferentes. Sin embargo, una instancia de una clase
+ persistente nunca se comparte entre dos instancias de <literal>Session</literal>.
+ Por lo tanto existen dos nociones diferentes de identidad:
+ </para>
+
+ <variablelist spacing="compact">
+ <varlistentry>
+ <term>Identidad de Base de Datos</term>
+ <listitem>
+ <para>
+ <literal>foo.getId().equals( bar.getId() )</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Identidad JVM</term>
+ <listitem>
+ <para>
+ <literal>foo==bar</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>
+ Entonces para objetos unidos a una <literal>Session</literal> <emphasis>en particular</emphasis>
+ (es decir en el ámbito de una <literal>Session</literal>) las dos nociones son equivalentes, y
+ la identidad JVM para la identidad de base de datos está garantizada por Hibernate. Sin embargo,
+ mientras la aplicación acceda concurrentemente al "mismo" (identidad persistente) objeto de negocio
+ en dos sesiones diferentes, las dos instancias serán realmente "diferentes" (identidad JVM).
+ Los conflictos se resuelven (con versionado automático) en tiempo de limpieza (flush) usando un
+ enfoque optimista.
+ </para>
+
+ <para>
+ Este enfoque deja que Hibernate y la base de datos se preocupen sobre la concurrencia. Además
+ provee la mejor escalabilidad, ya que garantizando la identidad un unidades de trabajo monohebra
+ no se necesitan bloqueos caros u otros medios de sincronización. La aplicación nunca necesita
+ sincronizar sobre ningún objeto de negocio, siempre que se apegue a una sola hebra por
+ <literal>Session</literal>. Dentro de una <literal>Session</literal> la aplicación puede usar
+ con seguridad <literal>==</literal> para comparar objetos.
+ </para>
+
+ <para>
+ Sin embargo, una aplicación que usa <literal>==</literal> fuera de una <literal>Session</literal>,
+ podría ver resultados inesperados. Esto podría ocurrir incluso en sitios algo inesperados,
+ por ejemplo, si pones dos instancias separadas dentro del mismo <literal>Set</literal>.
+ Ambas podrían tener la misma identidad de base de datos (es decir, representar la misma fila),
+ pero la identidad JVM, por definición, no está garantizada para las instancias en estado separado.
+ El desarrollador tiene que sobrescribir los métodos <literal>equals()</literal> y
+ <literal>hashCode()</literal> en las clases persistentes e implementar su propia noción de igualdad
+ de objetos. Hay una advertencia: Nunca uses el identificador de base de datos para implementar
+ la igualdad, usa una clave de negocio, una combinación de atributos únicos, usualmente inmutables.
+ El identificador de base de datos cambiará si un objeto transitorio es hecho persistente.
+ Si la instancia transitoria (usualmente junta a instancias separadas) es mantenida en un
+ <literal>Set</literal>, cambiar el código hash rompe el contrato del <literal>Set</literal>.
+ Los atributos para las claves de negocio no tienen que ser tan estables como las claves primarias
+ de base de datos, sólo tienes que garantizar estabilidad en tanto los objetos estén en el mismo
+ <literal>Set</literal>. Mira el sitio web de Hibernate para una discusión más cuidadosa de este
+ tema. Nota también que éste no es un tema de Hibernate, sino simplemente cómo la identidad y la igualdad
+ de los objetos Java tiene que ser implementada.
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-basics-issues">
+ <title>Temas comunes</title>
+
+ <para>
+ Nunca uses los antipatrones <emphasis>sesión-por-sesión-de-usuario</emphasis> o
+ <emphasis>sesión-por-aplicación</emphasis> (por supuesto, hay raras excepciones a esta
+ regla). Nota que algunis de los siguientes temas podrían también aparecer con los patrones
+ recomendados. Asegúrate que entiendes las implicaciones antes de tomar una decisión de
+ diseño:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>
+ Una <literal>Session</literal> no es segura entre hebras. Las cosas que se suponen
+ que funcionan concurrentemente, como peticiones HTTP, beans de sesión, o workers de
+ Swing, provocarán condiciones de competencia si una instancia de <literal>Session</literal>
+ fuese compartida. Si guardas tu <literal>Session</literal> de Hibernate en tu
+ <literal>HttpSession</literal> (discutido más adelante), debes considerar sincronizar
+ el acceso a tu sesión HTTP. De otro modo, un usuario que hace click lo suficientemente
+ rápido puede llegar a usar la misma <literal>Session</literal> en dos hebras ejecutándose
+ concurrentemente.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Una excepción lanzada por Hibernate significa que tienes que deshacer (rollback) tu
+ transacción de base de datos y cerrar la <literal>Session</literal> inmediatamente
+ (discutido en más detalle luego). Si tu <literal>Session</literal> está ligada a la
+ aplicación, tienes que parar la aplicación. Deshacer (rollback) la transacción de base
+ de datos no pone a tus objetos de vuelta al estado en que estaban al comienzo de la
+ transacción. Esto significa que el estado de la base de datos y los objetos de negocio
+ quedan fuera de sincronía. Usualmente esto no es un problema, pues las excepciones no
+ son recuperables y tienes que volver a comenzar después del rollback de todos modos.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ La <literal>Session</literal> pone en caché todo objeto que esté en estado persistente
+ (vigilado y chequeado por estado sucio por Hibernate). Esto significa que crece sin
+ fin hasta que obtienes una OutOfMemoryException, si la mantienes abierta por un largo
+ tiempo o simplemente cargas demasiados datos. Una solución para esto es llamar a
+ <literal>clear()</literal> y <literal>evict()</literal> para gestionar el caché de la
+ <literal>Session</literal>, pero probalemente debas considerar un procedimiento almacenado
+ si necesitas operaciones de datos masivas. Se muestran algunas soluciones en
+ <xref linkend="batch"/>. Mantener una <literal>Session</literal> abierta por la duración
+ de una sesión de usuario significa también una alta probabilidad de datos añejos.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="transactions-demarcation">
+ <title>Demarcación de la transacción de base de datos</title>
+
+ <para>
+ Los límites de las transacciones de base de datos (o sistema) son siempre necesarios. Ninguna comunicación
+ con la base de datos puede darse fuera de una transacción de base de datos (esto parece confundir muchos
+ desarrolladores acostumbrados al modo auto-commit). Siempre usa límites de transacción claros, incluso
+ para las operaciones de sólo lectura. Dependiendo del nivel de aislamiento y las capacidades de base de
+ datos, esto podría o no ser requerido, pero no hay un merma si siempre demarcas explícitamente
+ las transacciones.
+ </para>
+
+ <para>
+ Una aplicación Hibernate puede ejecutarse en entornos no manejados (es decir, como independiente,
+ Web simple, o aplicaciones Swing) y entornos manejados J2EE. En un entorno no manejado, Hibernate es
+ usualmente responsable de su propio pool de conexiones de base de datos. El desarrollador de aplicaciones
+ tiene que establecer manualmente los límites de transacción, en otras palabras, hacer begin, commit, o
+ rollback las transacciones de base de datos por sí mismo. Un entorno manejado usualmente provee transacciones
+ gestionadas por contenedor, con el ensamble de transacción definido declarativamente en descriptores de
+ despliegue de beans de sesión EJB, por ejemplo. La demarcación programática de transacciones no es más
+ necesario, incluso limpiar (flush) la <literal>Session</literal> es hecho automáticamente.
+ </para>
+
+ <para>
+ Sin embargo, frecuentemente es deseable mantener portable tu capa de persistencia. Hibernate ofrece
+ una API de envoltura llamada <literal>Transaction</literal> que se traduce al sistema de transacciones
+ nativo de tu entorno de despliegue. Esta API es realmente opcional, pero recomendamos fuertemente su uso
+ salvo que estés en un bean de sesión CMT.
+ </para>
+
+ <para>
+ Usualmente, finalizar una <literal>Session</literal> implica cuatro fases distintas:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ limpiar (flush) la sesión
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ comprometer la transacción
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ cerrar la sesión
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ manejar excepciones
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Limpiar la sesión ha sido discutido anteriormente, tendremos ahora una mirada más de cerca
+ a la demarcación de transacciones y manejo de excepciones en sendos entornos manejado y no manejados.
+ </para>
+
+
+ <sect2 id="transactions-demarcation-nonmanaged">
+ <title>Entorno no manejado</title>
+
+ <para>
+ Si una capa de persistencia Hibernate se ejecuta en un entorno no manejado, las conexiones
+ de base de datos son manejadas usualmente por el mecanismo de pooling de Hibernate. El idioma
+ manejo de sesión/transacción se ve así:
+ </para>
+
+ <programlisting><![CDATA[//Non-managed environment idiom
+Session sess = factory.openSession();
+Transaction tx = null;
+try {
+ tx = sess.beginTransaction();
+
+ // do some work
+ ...
+
+ tx.commit();
+}
+catch (RuntimeException e) {
+ if (tx != null) tx.rollback();
+ throw e; // or display error message
+}
+finally {
+ sess.close();
+}]]></programlisting>
+
+ <para>
+ No tienes que limpiar con <literal>flush()</literal> la <literal>Session</literal> explícitamente -
+ la llamada a <literal>commit()</literal> automáticamente dispara la sincronización.
+ </para>
+
+ <para>
+ Una llamada a <literal>close()</literal> marca el fin de una sesión. La principal implicación
+ de <literal>close()</literal> es que la conexión JDBC será abandonada por la sesión.
+ </para>
+
+ <para>
+ Este código Java es portable y se ejecuta tanto en entornos no manejados como en entornos JTA.
+ </para>
+
+ <para>
+ Muy probablemente nunca veas este idioma en código de negocio en una aplicación normal;
+ las excepciones fatales (sistema) deben siempre ser capturadas en la "cima". En otras palabras,
+ el código que ejecuta las llamadas de Hibernate (en la capa de persistencia) y el código que
+ maneja <literal>RuntimeException</literal> (y usualmente sólo puede limpiar y salir) están en
+ capas diferentes. Esto puede ser un desafío de diseñarlo tú mismo y debes usar los servicios
+ de contenedor J2EE/EJB en cuanto estuviesen disponibles. El manejo de excepciones se dicute
+ más adelante en este capítulo.
+ </para>
+
+ <para>
+ Nota que debes seleccionar <literal>org.hibernate.transaction.JDBCTransactionFactory</literal>
+ (que es el por defecto).
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-demarcation-jta">
+ <title>Usando JTA</title>
+
+ <para>
+ Si tu capa de persistencia se ejecuta en un servidor de aplicaciones (por ejemplo, detrás
+ de beans de sesión EJB), cada conexión de datasource obtenida por Hibernate será parte
+ automáticamente de la transacción JTA global. Hibernate ofrece dos estrategias para esta
+ integración.
+ </para>
+
+ <para>
+ Si usas transacciones gestionadas-por-bean (BMT) Hibernate le dirá al servidor de aplicaciones
+ que comience y finalice una transacción BMT si usas la API de <literal>Transaction</literal>.
+ De modo que, el código de gestión de la transacción es idéntico al de un entorno no manejado.
+ </para>
+
+ <programlisting><![CDATA[// BMT idiom
+Session sess = factory.openSession();
+Transaction tx = null;
+try {
+ tx = sess.beginTransaction();
+
+ // do some work
+ ...
+
+ tx.commit();
+}
+catch (RuntimeException e) {
+ if (tx != null) tx.rollback();
+ throw e; // or display error message
+}
+finally {
+ sess.close();
+}]]></programlisting>
+
+ <para>
+ Con CMT, la demarcación de la transacción se hace en descriptores de despliegue de beans de sesión,
+ no programáticamente. Si no quieres limpiar (flush) y cerrar manualmente la <literal>Session</literal>
+ por ti mismo, solamente establece <literal>hibernate.transaction.flush_before_completion</literal> a
+ <literal>true</literal>, <literal>hibernate.connection.release_mode</literal> a
+ <literal>after_statement</literal> o <literal>auto</literal> y
+ <literal>hibernate.transaction.auto_close_session</literal> a <literal>true</literal>. Hibernate
+ limpiará y cerrará entonces automáticamente la <literal>Session</literal> para ti. Lo único que resta
+ es deshacer (rollback) la transacción cuando ocurra una excepción. Afortunadamente, en un bean CMT,
+ incluso esto ocurre automáticamente, ya que una <literal>RuntimeException</literal> no manejada
+ disparada por un método de un bean de sesión le dice al contenedor que ponga a deshacer la transacción
+ global. <emphasis>Esto significa que, en CMT, no necesitas usar en absoluto la API de
+ <literal>Transaction</literal> de Hibernate.</emphasis>
+ </para>
+
+ <para>
+ Nota que debes elegir <literal>org.hibernate.transaction.JTATransactionFactory</literal> en un
+ bean de sesión BMT, y <literal>org.hibernate.transaction.CMTTransactionFactory</literal> en un
+ bean de sesión CMT, cuando configures la fábrica de transacciones de Hibernate. Recuerda además
+ establecer <literal>org.hibernate.transaction.manager_lookup_class</literal>.
+ </para>
+
+ <para>
+ Si trabajas en un entorno CMT, y usas limpieza (flushing) y cierre automáticos de la sesión,
+ podrías querer también usar la misma sesión en diferentes partes de tu código. Típicamente,
+ en un entorno no manejado, usarías una variable <literal>ThreadLocal</literal> para tener la sesión,
+ pero una sola petición de EJB puede ejecutarse en diferentes hebras (por ejemplo, un bean de sesión
+ llamando a otro bean de sesión). Si no quieres molestarte en pasar tu <literal>Session</literal>
+ por alrededor, la <literal>SessionFactory</literal> provee el método
+ <literal>getCurrentSession()</literal>, que devuelve una sesión que está pegada al contexto de
+ transacción JTA. ¡Esta es la forma más fácil de integrar Hibernate en una aplicación!
+ La sesión "actual" siempre tiene habilitados limpieza, cierre y liberación de conexión automáticos
+ (sin importar la configuración de las propiedades anteriores). Nuestra idioma de gestión de
+ sesión/transacción se reduce a:
+ </para>
+
+ <programlisting><![CDATA[// CMT idiom
+Session sess = factory.getCurrentSession();
+
+// do some work
+...
+
+]]></programlisting>
+
+ <para>
+ En otras palabras, todo lo que tienes que hacer en un entorno manejado, es llamar a
+ <literal>SessionFactory.getCurrentSession()</literal>, hacer tu trabajo de acceso a datos,
+ y dejar el resto al contenedor. Los límites de transacción se establecen declarativamente
+ en los descriptores de despliegue de tu bean de sesión. El ciclo de vida de la sesión es
+ manejado completamente por Hibernate.
+ </para>
+
+ <para>
+ Existe una advertencia al uso del modo de liberación de conexión <literal>after_statement</literal>.
+ Debido a una limitación tonta de la especificación de JTA, no es posible para Hibernate
+ limpiar automáticamente ningún <literal>ScrollableResults</literal> no cerrado ni
+ instancias de <literal>Iterator</literal> devueltas por <literal>scroll()</literal> o
+ <literal>iterate()</literal>. <emphasis>Debes</emphasis> liberar el cursor de base de datos
+ subyacente llamando a <literal>ScrollableResults.close()</literal> o
+ <literal>Hibernate.close(Iterator)</literal> explícitamente desde un bloque <literal>finally</literal>.
+ (Por supuesto, la mayoría de las aplicaciones pueden evitarlo fácilmente no usando en absoluto ningún
+ <literal>scroll()</literal> o <literal>iterate()</literal> desde el código CMT.)
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-demarcation-exceptions">
+ <title>Manejo de excepciones</title>
+
+ <para>
+ Si la <literal>Session</literal> lanza una excepción (incluyendo cualquier
+ <literal>SQLException</literal>), debes inmediatamente deshacer (rollback) la
+ transacción de base de datos, llamar a <literal>Session.close()</literal> y
+ descartar la instancia de <literal>Session</literal>. Ciertos métodos de
+ <literal>Session</literal> <emphasis>no</emphasis> dejarán la sesión en un
+ estado consistente. Ninguna excepción lanzada por Hibernate puede ser tratada
+ como recuperable. Asegúrate que la <literal>Session</literal> sea cerrada llamando
+ a <literal>close()</literal> en un bloque <literal>finally</literal>.
+ </para>
+
+ <para>
+ La <literal>HibernateException</literal>, que envuelve la mayoría de los errores que
+ pueden ocurrir en la capa de persistencia de Hibernate, en una excepción no chequeada
+ (no lo era en versiones anteriores de Hibernate). En nuestra opinión, no debemos forzar
+ al desarrollador de aplicaciones a capturar una excepción irrecuperable en una capa baja.
+ En la mayoría de los sistemas, las excepciones no chequeadas y fatales son manejadas
+ en uno de los primeros cuadros de la pila de llamadas a métodos (es decir, en las capas
+ más altas) y se presenta un mensaje de error al usuario de la aplicación (o se toma alguna
+ otra acción apropiada). Nota que Hibernate podría también lanzar otras excepciones no chequeadas
+ que no sean una <literal>HibernateException</literal>. Una vez más, no son recuperables y debe
+ tomarse una acción apropiada.
+ </para>
+
+ <para>
+ Hibernate envuelve <literal>SQLException</literal>s lanzadas mientras se interactúa con la base
+ de datos en una <literal>JDBCException</literal>. De hecho, Hibernate intentará convertir la excepción
+ en una subclase de <literal>JDBCException</literal> más significativa. La <literal>SQLException</literal>
+ está siempre disponible vía <literal>JDBCException.getCause()</literal>. Hibernate convierte la
+ <literal>SQLException</literal> en una subclase de <literal>JDBCException</literal> apropiada usando
+ el <literal>SQLExceptionConverter</literal> adjunto a la <literal>SessionFactory</literal>. Por defecto,
+ el <literal>SQLExceptionConverter</literal> está definido para el dialecto configurado; sin embargo,
+ es también posible enchufar una implementación personalizada (ver los javadocs de la clase
+ <literal>SQLExceptionConverterFactory</literal> para los detalles). Los subtipos estándar de
+ <literal>JDBCException</literal> son:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>JDBCConnectionException</literal> - indica un error con la comunicación JDBC subyacente.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>SQLGrammarException</literal> - indica un problema de gramática o sintáxis con el
+ SQL publicado.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>ConstraintViolationException</literal> - indica alguna forma de violación de restricción
+ de integridad.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>LockAcquisitionException</literal> - indica un error adquiriendo un nivel de bloqueo
+ necesario para realizar una operación solicitada.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>GenericJDBCException</literal> - una excepción genérica que no cayó en ninguna de las
+ otras categorías.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="transactions-optimistic">
+ <title>Control optimista de concurrencia</title>
+
+ <para>
+ El único enfoque que es consistente con alta concurrencia y alta escalabilidad es el control
+ optimista de concurrencia con versionamiento. El chuequeo de versión usa números de versión,
+ o timestamps, para detectar actualizaciones en conflicto (y para prevenir actualizaciones perdidas).
+ Hibernate provee para tres enfoques posibles de escribir código de aplicación que use concurrencia
+ optimista. Los casos de uso que hemos mostrado están en el contexto de transacciones de aplicación
+ largas pero el chequeo de versiones tiene además el beneficio de prevenir actualizaciones perdidas
+ en transacciones de base de datos solas.
+ </para>
+
+ <sect2 id="transactions-optimistic-manual">
+ <title>Chequeo de versiones de aplicación</title>
+
+ <para>
+ En una implementación sin mucha ayuda de Hibernate, cada interacción con la base de datos ocurre en una
+ nueva <literal>Session</literal> y el desarrollador es responsable de recargar todas las intancias
+ persistentes desde la base de datos antes de manipularlas. Este enfoque fuerza a la aplicación a
+ realizar su propio chequeo de versiones para asegurar el aislamiento de transacciones de base de datos.
+ Es el enfoque más similar a los EJBs de entidad.
+ </para>
+
+ <programlisting><![CDATA[// foo is an instance loaded by a previous Session
+session = factory.openSession();
+Transaction t = session.beginTransaction();
+int oldVersion = foo.getVersion();
+session.load( foo, foo.getKey() ); // load the current state
+if ( oldVersion != foo.getVersion() ) throw new StaleObjectStateException();
+foo.setProperty("bar");
+t.commit();
+session.close();]]></programlisting>
+
+ <para>
+ La propiedad <literal>version</literal> se mapea usando <literal><version></literal>,
+ e Hibernate la incrementará automáticamente durante la limpieza si la entidad está sucia.
+ </para>
+
+ <para>
+ Por supuesto, si estás operando un entorno de baja-concurrencia-de-datos y no requieres
+ chequeo de versiones, puedes usar este enfoque y simplemente saltar el chequeo de versiones.
+ En ese caso, <emphasis>el último compromiso (commit) gana</emphasis> será la estrategia por
+ defecto para tus transacciones de aplicación largas. Ten en mente que esto podría confundir
+ a los usuarios de la aplicación, pues podrían experimentar actualizaciones perdidas sin
+ mensajes de error ni chance de fusionar los cambios conflictivos.
+ </para>
+
+ <para>
+ Claramente, el chequeo manual de versiones es factible solamente en circunstancias muy triviales,
+ y no es práctico para la mayoría de aplicaciones. Frecuentemente, no sólo intancias solas, sino grafos
+ completos de objetos modificados tienen que ser chequeados. Hibernate ofrece chequeo de versiones
+ automático con el paradigma de diseño de <literal>Session</literal> larga o de instancias separadas.
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-optimistic-longsession">
+ <title>Sesión larga y versionado automático</title>
+
+ <para>
+ Una sola instancia de <literal>Session</literal> y sus instancias persistentes
+ son usadas para toda la transacción de aplicación. Hibernate chequea las versiones
+ de instancia en el momento de limpieza (flush), lanzando una excepción si se detecta
+ una modificación concurrente. Concierne al desarrollador capturar y manejar esta excepción
+ (las opciones comunes son la oportunidad del usuario de fusionar los cambios, o recomenzar el
+ proceso de negocio sin datos añejos).
+ </para>
+
+ <para>
+ La <literal>Session</literal> se desconecta de cualquier conexión JDBC subyacente
+ al esperar por una interacción del usuario. Este enfoque es el más eficiente en términos
+ de acceso a base de datos. La aplicación no necesita tratar por sí misma con el chequeo de
+ versiones, ni re-uniendo instancias separadas, ni tiene que recargar instancias en cada
+ transacción de base de datos.
+ </para>
+
+ <programlisting><![CDATA[// foo is an instance loaded earlier by the Session
+session.reconnect(); // Obtain a new JDBC connection
+Transaction t = session.beginTransaction();
+foo.setProperty("bar");
+t.commit(); // End database transaction, flushing the change and checking the version
+session.disconnect(); // Return JDBC connection ]]></programlisting>
+
+ <para>
+ El objeto <literal>foo</literal> todavía conoce en qué <literal>Session</literal> fue cargado.
+ <literal>Session.reconnect()</literal> obtiene una nueva conexión (o puedes proveer una) y
+ reasume la sesión. El método <literal>Session.disconnect()</literal> desconectará la sesión
+ de la conexión JDBC y la devolverá la conexión al pool (a menos que hayas provisto la conexión).
+ Después de la reconexión, para forzar un chequeo de versión en datos que no estés actualizando,
+ puedes llamar a <literal>Session.lock()</literal> con <literal>LockMode.READ</literal> sobre
+ cualquier objeto que pudiese haber sido actualizado por otra transacción. No necesitas bloquear
+ ningún dato que <emphasis>sí estés</emphasis> actualizando.
+ </para>
+
+ <para>
+ Si las llamadas explícitas a <literal>disconnect()</literal> y <literal>reconnect()</literal>
+ son muy onerosas, puedes usar en cambio <literal>hibernate.connection.release_mode</literal>.
+ </para>
+
+ <para>
+ Este patrón es problemático si la <literal>Session</literal> es demasiado grande para ser almacenada
+ durante el tiempo de pensar del usuario, por ejemplo, una <literal>HttpSession</literal> debe
+ mantenerse tan pequeña como sea posible. Ya que la <literal>Session</literal> es también el caché
+ (obligatorio) de primer nivel y contiene todos los objetos cargados, podemos probablemente cargar
+ esta estrategia sólo para unos pocos ciclos petición/respuesta. Esto está de hecho recomendado, ya que
+ la <literal>Session</literal> tendrá pronto también datos añejos.
+ </para>
+
+ <para>
+ Nota también que debes mantener la <literal>Session</literal> desconectada próxima a la capa
+ de persistencia. En otras palabras, usa una sesión de EJB con estado para tener la
+ <literal>Session</literal> y no transferirla a la capa web para almacenarla en la
+ <literal>HttpSession</literal> (ni incluso serializarla a una capa separada).
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-optimistic-detached">
+ <title>Objetos separados y versionado automático</title>
+
+ <para>
+ Cada interacción con el almacén persistente ocurre en una nueva <literal>Session</literal>.
+ Sin embargo, las mismas instancias persistentes son reusadas para cada interacción con la base de
+ datos. La aplicación manipula el estado de las instancias separadas originalmente cargadas en otra
+ <literal>Session</literal> y luego las readjunta usando <literal>Session.update()</literal>,
+ <literal>Session.saveOrUpdate()</literal>, o <literal>Session.merge()</literal>.
+ </para>
+
+ <programlisting><![CDATA[// foo is an instance loaded by a previous Session
+foo.setProperty("bar");
+session = factory.openSession();
+Transaction t = session.beginTransaction();
+session.saveOrUpdate(foo); // Use merge() if "foo" might have been loaded already
+t.commit();
+session.close();]]></programlisting>
+
+ <para>
+ De nuevo, Hibernate chequeará las versiones de instancia durante la limpieza (flush),
+ lanzando una excepción si ocurrieron actualizaciones en conflicto.
+ </para>
+
+ <para>
+ Puedes también llamar a <literal>lock()</literal> en vez de <literal>update()</literal>
+ y usar <literal>LockMode.READ</literal> (realizando un chequeo de versión, puenteando
+ todos los cachés) si estás seguro que el objeto no ha sido modificado.
+ </para>
+
+ </sect2>
+
+ <sect2 id="transactions-optimistic-customizing">
+ <title>Personalizando el versionado automático</title>
+
+ <para>
+ Puedes deshabilitar el incremento de versión automático de Hibernate para propiedades en particular
+ y colecciones estableciendo el atributo de mapeo <literal>optimistic-lock</literal> a
+ <literal>false</literal>. Hibernate entonces no incrementará ya más las versiones si la propiedad está
+ sucia.
+ </para>
+
+ <para>
+ Los esquemas de base de datos heredados son frecuentemente estáticos y no pueden ser modificados.
+ U otras aplicaciones podrían también acceder la misma base de datos y no saber cómo manejar los números
+ de versión ni incluso timestamps. En ambos casos, el versionado no puede confiarse a una columna en
+ particular en una tabla. Para forzar un chequeo de versiones sin un mapeo de propiedad de versión o
+ timestamp, con una comparación del estado de todos los campos en una fila, activa
+ <literal>optimistic-lock="all"</literal> en el mapeo de <literal><class></literal>.
+ Nota que esto conceptualmente funciona solamente si Hibernate puede comparar el estado viejo y nuevo,
+ es decir, si usas una sola <literal>Session</literal> larga y no
+ sesión-por-petición-con-instancias-separadas.
+ </para>
+
+ <para>
+ A veces las modificaciones concurrentes pueden permitirse, en cuanto los cambios que hayan sido
+ hechos no se traslapen. Si estableces <literal>optimistic-lock="dirty"</literal> al mapear la
+ <literal><class></literal>, Hibernate sólo comparará los campos sucios durante la limpieza.
+ </para>
+
+ <para>
+ En ambos casos, con columnas de versión/timestamp dedicadas o con comparación de campos
+ completa/sucios, Hibernate usa una sola sentencia <literal>UPDATE</literal>
+ (con una cláusula <literal>WHERE</literal> apropiada) por entidad para ejecutar el chequeo
+ de versiones y actualizar la información. Si usas persistencia transitiva para la re-unión
+ en cascada de entidades asociadas, Hibernate podría ejecutar actualizaciones innecesarias.
+ Esto usualmente no es un problema, pero podrían ejecutarse disparadores (triggers)
+ <emphasis>on update</emphasis> en la base de datos incluso cuando no se haya hecho ningún cambio
+ a las instancias separadas. Puedes personalizar este comportamiento estableciendo
+ <literal>select-before-update="true"</literal> en el mapeo de <literal><class></literal>,
+ forzando a Hibernate a <literal>SELECT</literal> la instancia para asegurar que las actualizaciones
+ realmente ocurran, antes de actualizar la fila.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="transactions-locking">
+ <title>Bloqueo pesimista</title>
+
+ <para>
+ No se pretende que los usuarios gasten mucho tiempo preocupándose de las estrategias de bloqueo.
+ Usualmente es suficiente con especificar un nivel de aislamiento para las conexiones JDBC y entonces
+ simplemente dejar que la base de datos haga todo el trabajo. Sin embargo, los usuarios avanzados pueden
+ a veces obtener bloqueos exclusivos pesimistas, o reobtener bloqueos al comienzo de una nueva
+ transacción.
+ </para>
+
+ <para>
+ ¡Hibernate siempre usará el mecanismo de bloqueo de la base de datos, nunca bloqueo
+ de objetos en memoria!
+ </para>
+
+ <para>
+ La clase <literal>LockMode</literal> define los diferentes niveles de bloqueo que pueden ser adquiridos
+ por Hibernate. Un bloqueo se obtiene por los siguientes mecanismos:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>LockMode.WRITE</literal> se adquiere automáticamente cuando Hibernate actualiza o
+ inserta una fila.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>LockMode.UPGRADE</literal> puede ser adquirido bajo petición explícita del usuario
+ usando <literal>SELECT ... FOR UPDATE</literal> en base de datos que soporten esa sintáxis.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>LockMode.UPGRADE_NOWAIT</literal> puede ser adquirido bajo petición explícita del usuario
+ usando un <literal>SELECT ... FOR UPDATE NOWAIT</literal> bajo Oracle.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>LockMode.READ</literal> es adquirido automáticamente cuando Hibernate lee datos
+ bajo los niveles de aislamiento Repeatable Read o Serializable. Puede ser readquirido por
+ pedido explícito del usuario.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>LockMode.NONE</literal> representa la ausencia de un bloqueo. Todos los objetos se pasan
+ a este modo de bloqueo al final de una <literal>Transaction</literal>. Los objetos asociados con una
+ sesión vía una llamada a <literal>update()</literal> o <literal>saveOrUpdate()</literal> también
+ comienzan en este modo de bloqueo.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ La "petición explícita del usuario" se expresa en una de las siguientes formas:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ Una llamada a <literal>Session.load()</literal>, especificando un <literal>LockMode</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Una llamada a <literal>Session.lock()</literal>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Una llamada a <literal>Query.setLockMode()</literal>.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Si se llama a <literal>Session.load()</literal> con <literal>UPGRADE</literal> o
+ <literal>UPGRADE_NOWAIT</literal>, y el objeto pedido no ha sido aún cargado por la sesión, el objeto es
+ cargado usando <literal>SELECT ... FOR UPDATE</literal>. Si se llama a <literal>load()</literal> para
+ un objeto que ya esté cargado con un bloqueo menos restrictivo que el pedido, Hibernate llama a
+ <literal>lock()</literal> para ese objeto.
+ </para>
+
+ <para>
+ <literal>Session.lock()</literal> realiza un chequeo de número de versión si el modo de bloqueo especificado
+ es <literal>READ</literal>, <literal>UPGRADE</literal> o <literal>UPGRADE_NOWAIT</literal>. (En el caso de
+ <literal>UPGRADE</literal> o <literal>UPGRADE_NOWAIT</literal>, se usa
+ <literal>SELECT ... FOR UPDATE</literal>.)
+ </para>
+
+ <para>
+ Si la base de datos no soporta el modo de bloqueo solicitado, Hibernate usará un modo alternativo
+ apropiado (en vez de lanzar una excepción). Esto asegura que las aplicaciones serán portables.
+ </para>
+
+ </sect1>
+
+</chapter>
+
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/content/tutorial.xml (from rev 12794, core/trunk/documentation/manual/es-ES/src/main/docbook/modules/tutorial.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/tutorial.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/tutorial.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,1270 @@
+<chapter id="tutorial">
+ <title>Introducción a Hibernate</title>
+
+ <sect1 id="tutorial-intro">
+ <title>Prefacio</title>
+
+ <para>
+ Este capítulo es un tutorial introductorio de Hibernate. Comenzamos con
+ una aplicación simple de línea de comandos usando un base de datos
+ en-memoria y desarrollándola en fácil para entender los pasos.
+ </para>
+
+ <para>
+ Este tutorial está concebido para usuarios nuevos de Hibernate pero
+ requiere conocimiento en Java y SQL. Está basado en un tutorial de
+ Michael Gloegl. Las bibliotecas de terceros que mencionamos son para JDK 1.4
+ y 5.0. Podrías necesitar otras para JDK 1.3.
+ </para>
+
+ </sect1>
+
+ <sect1 id="tutorial-firstapp">
+ <title>Parte 1 - La primera Aplicación Hibernate</title>
+
+ <para>
+ Primero, crearemos una aplicación simple de Hibenate basada en consola.
+ Usamos usamos una base de datos en-memoria (HSQL DB), de modo que no necesitamos
+ instalar ningún servidor de base de datos.
+ </para>
+
+ <para>
+ Asumamos que necesitamos una aplicación pequeña de base de datos que
+ pueda almacenar eventos que queremos atender, e información acerca de los
+ hostales de estos eventos.
+ </para>
+
+ <para>
+ La primera cosa que hacemos, es armar nuestro directorio de desarrollo y poner
+ en él todas las bibliotecas Java que necesitamos. Descarga la distribución
+ de Hibernate del sitio web de Hibernate. Extrae el paquete y coloca todas las
+ bibliotecas requeridas encontradas en <literal>/lib</literal> dentro del directorio
+ <literal>/lib</literal> de nuestro nuevo directorio de desarrollo de trabajo.
+ Debe asemejarse a esto:
+ </para>
+
+ <programlisting><![CDATA[.
++lib
+ antlr.jar
+ cglib-full.jar
+ asm.jar
+ asm-attrs.jars
+ commons-collections.jar
+ commons-logging.jar
+ ehcache.jar
+ hibernate3.jar
+ jta.jar
+ dom4j.jar
+ log4j.jar ]]></programlisting>
+
+ <para>
+ Este es el conjunto mínimo de bibliotecas requeridas para Hibernate (observa que
+ también hemos copiado hibernate3.jar, el fichero principal). Ver el fichero
+ <literal>README.txt</literal> en el directorio <literal>lib/</literal> de la distribución
+ de Hibernate para más información sobre bibliotecas de terceros requeridas y
+ opcionales. (Realmente, Log4J no es requerida aunque preferida por muchos desarrolladores).
+ </para>
+
+ <para>
+ Por siguiente, creamos una clase que represente el evento que queremos
+ almacenar en base de datos.
+ </para>
+
+ <sect2 id="tutorial-firstapp-firstclass">
+ <title>La primera clase</title>
+
+ <para>
+ Nuestra primera clase persistente es un JavaBean simple con algunas propiedades:
+ </para>
+
+ <programlisting><![CDATA[import java.util.Date;
+
+public class Event {
+ private Long id;
+
+ private String title;
+ private Date date;
+
+ 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;
+ }
+}]]></programlisting>
+
+ <para>
+ Puedes ver que esta clase usa las convenciones de nombrado estándar de JavaBean
+ para métodos getter y setter de propiedad, así como visibilidad privada
+ para los campos. Esto es un diseño recomendado, aunque no requerido. Hibernate
+ también puede acceder a los campos directamente; el beneficio de los métodos
+ de acceso es la robustez para la refactorización.
+ </para>
+
+ <para>
+ La propiedad <literal>id</literal> tiene un valor único de identificador para
+ un evento en particular. Todas las clase de entidad persistentes ( también hay
+ clases dependientes menos importantes) necesitarán una propiedad identificadora
+ similar si queremos usar el conjunto completo de funcionalidades de Hibernate. De hecho,
+ la mayoría de las aplicaciones (esp. aplicaciones web) necesitan distinguir
+ objetos por identificador, de modo que debes considerar esto como un aspecto en vez de una
+ limitación. Sin embargo, usualmente no manipulamos la identidad de un objeto, por
+ lo tanto el método setter debe ser privado. Sólo Hibernate asignará
+ identificadores cuando un objeto sea salvado. Puedes ver que Hibernate puede acceder a
+ métodos de acceso públicos, privados y protegidos, tanto como directamente a
+ campos (públicos, privados y protegidos). La elección está en ti,
+ y puedes ajustarla a tu diseño de aplicación.
+ </para>
+
+ <para>
+ El constructor sin argumentos es un requerimiento para todas las clases persistentes.
+ Hibernate tiene que crear objetos para ti, usando reflección Java. El constructor
+ puede ser privado, sin embargo, la visibilidad de paquete es requerida para la generación
+ de proxies en tiempo de ejecución y la recuperación de datos sin
+ instrumentación del bytecode.
+ </para>
+
+ <para>
+ Coloca este fichero de código Java en un directorio llamado <literal>src</literal>
+ en la carpeta de desarrollo. El directorio ahora debe verse como esto:
+ </para>
+
+ <programlisting><![CDATA[.
++lib
+ <Hibernate and third-party libraries>
++src
+ Event.java]]></programlisting>
+
+ <para>
+ En el próximo paso, le decimos a Hibernate sobre esta clase persistente.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-firstapp-mapping">
+ <title>El fichero de mapeo</title>
+
+ <para>
+ Hibernate necesita saber cómo cargar y almacenar objetos de la
+ clase persistente. Aquí es donde el fichero de mapeo de Hibernate
+ entra en juego. El fichero de mapeo le dice a Hibernate a qué tabla en
+ la base de datos tiene que acceder, y qué columnas en esta tabla debe usar.
+ </para>
+
+ <para>
+ La estructura básica de un fichero de mapeo se parece a esto:
+ </para>
+
+ <programlisting><![CDATA[<?xml version="1.0"?>
+<!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
+
+<hibernate-mapping>
+[...]
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Observa que el DTD de Hibernate es muy sofisticado. Puedes usarlo para
+ autocompleción de los elementos y atributos XML de mapeo en tu
+ editor o IDE. Debes también abrir el fichero DTD en tu editor de
+ texto. Es la forma más fácil para tener un panorama de todos
+ los elementos y atributos y ver los valores por defectos, así como
+ algunos comentarios. Nota que Hibernate no cargará el fichero DTD de
+ la web, sino que primero buscará en el classpath de la aplicación.
+ El fichero DTD está incluído en <literal>hibernate3.jar</literal>
+ así como también en el directorio <literal>src/</literal> de la
+ distribución de Hibernate.
+ </para>
+
+ <para>
+ Omitiremos la declaración de DTD en futuros ejemplos para acortar
+ el código. Por supuesto, no es opcional.
+ </para>
+
+ <para>
+ Entre las dos etiquetas <literal>hibernate-mapping</literal>, incluye
+ un elemento <literal>class</literal>. Todas las clases de entidad
+ persistentes (de nuevo, podría haber más adelante clases
+ dependientes, que no sean entidades de-primera-clase) necesitan dicho mapeo
+ a una tabla en la base de datos SQL:
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Event" table="EVENTS">
+
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Hasta ahora dijimos a Hibernate cómo persistir y cargar el objeto
+ de clase <literal>Event</literal> a la tabla <literal>EVENTS</literal>,
+ cada instancia representada por una fila en esta tabla. Ahora continuamos con
+ un mapeo de la propiedad de identificado único a la clave primaria
+ de la tabla. Además, como no queremos cuidar del manejo de este identificador,
+ configuramos la estrategia de generación de identificadores para una columna
+ clave primaria delegada:
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Event" table="EVENTS">
+ <id name="id" column="EVENT_ID">
+ <generator class="increment"/>
+ </id>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ El elemento <literal>id</literal> el la declaración de la propiedad
+ identificadora, <literal>name="id"</literal> declara el nombre de la
+ propiedad Java. Hibernate usará los métodos getter y setter
+ para acceder a la propiedad. El attributo de columna dice a Hibernate cuál
+ columna de la tabla <literal>EVENTS</literal> usamos para esta clave primaria.
+ El elemento anidado <literal>generator</literal> especifica la estrategia de
+ generación de identificadores, en este caso usamos <literal>increment</literal>,
+ que es un método muy simple de incremento de número en-memoria
+ útil mayormente para testeo (y tutoriales). Hibernate también
+ soporta identificadores generados por base de datos, globalmente únicos,
+ así como también asignados por aplicación (o cualquier
+ estrategia para la que hayas escrito una extensión).
+ </para>
+
+ <para>
+ Finalmente incluímos declaraciones para las propiedades persistentes
+ de la clases en el fichero de mapeo. Por defecto, ninguna propiedad de la clase
+ se considera persistente:
+ </para>
+
+ <programlisting><![CDATA[
+<hibernate-mapping>
+
+ <class name="Event" table="EVENTS">
+ <id name="id" column="EVENT_ID">
+ <generator class="increment"/>
+ </id>
+ <property name="date" type="timestamp" column="EVENT_DATE"/>
+ <property name="title"/>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Al igual que con el elemento <literal>id</literal>, el atributo <literal>name</literal>
+ del elemento <literal>property</literal> dice a Hibernate cáles métodos
+ getter y setter usar.
+ </para>
+
+ <para>
+ ¿Por qué el mapeo de la propiedad <literal>date</literal>
+ incluye el atributo <literal>column</literal>, pero el de la de
+ <literal>title</literal> no? Sin el atributo <literal>column</literal>
+ Hibernate usa por defecto el nombre de propiedad como nombre de columna.
+ Esto funciona bien para <literal>title</literal>. Sin embargo,
+ However, <literal>date</literal> es una palabra reservada en la
+ mayoría de las bases de datos, así que mejor la mapeamos
+ a un nombre diferente.
+ </para>
+
+ <para>
+ La próxima cosa interesante es que el mapeo de <literal>title</literal>
+ carece de un atributo <literal>type</literal>. Los tipos que declaramos y usamos
+ en el fichero de mapeo no son, como podrías esperar, tipos de datos Java.
+ Tampoco son tipos de base de datos SQL. Estos tipos son los llamados así
+ <emphasis>Tipos de mapeo de Hibernate</emphasis>, convertidores que pueden
+ traducir de tipos Java a SQL y vice versa. De nuevo, Hibernate intentará
+ determinar la conversión y el mapeo mismo de tipo correctos si el atributo
+ <literal>type</literal> no estuviese presente en el mapeo. En algunos casos esta
+ detección automática (usando reflección en la clase Java)
+ puede no tener lo que esperas o necesitas. Este es el caso de la propiedad
+ <literal>date</literal>. Hibernate no puede saber is la propiedad mapeará
+ a una columna <literal>date</literal>, <literal>timestamp</literal> o
+ <literal>time</literal>. Declaramos que queremos preservar la información
+ completa de fecha y hora mapeando la propiedad con un <literal>timestamp</literal>.
+ </para>
+
+ <para>
+ Este fichero de mapeo debe ser salvado como <literal>Event.hbm.xml</literal>,
+ justo en el directorio próximo al fichero de código fuente de
+ la clase Java <literal>Event</literal>. El nombrado de los ficheros de mapeo
+ puede ser arbitrario, sin embargo, el sufijo <literal>hbm.xml</literal> se ha
+ vuelto una convención el la comunidad de desarrolladores de Hibernate.
+ La estructura de directorio debe ahora verse como esto:
+ </para>
+
+ <programlisting><![CDATA[.
++lib
+ <Hibernate and third-party libraries>
++src
+ Event.java
+ Event.hbm.xml]]></programlisting>
+
+ <para>
+ Continuamos con la configuración principal de Hibernate.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-firstapp-configuration">
+ <title>Configuración de Hibernate</title>
+
+ <para>
+ Tenemos ahora una clase persistente y su fichero de mapeo en su sitio. Es momento de
+ configurar Hibernate. Antes que hagamos esto, necesitaremos una base de datos.
+ HSQL DB, un DBMS SQL en-memoria basado en Java, puede ser descargado del sitio web
+ de HSQL DB. Realmente, de esta descarga sólo necesitas el <literal>hsqldb.jar</literal>.
+ Coloca este fichero en el directorio <literal>lib/</literal> de la carpeta de desarrollo.
+ </para>
+
+ <para>
+ Crea un directorio llamado <literal>data</literal> en la raíz del directorio de
+ desarrollo. Allí es donde HSQL DB almacenará sus ficheros de datos.
+ </para>
+
+ <para>
+ Hibernate es la capa en tu aplicación que se conecta a esta base de datos,
+ de modo que necesita información de conexión. Las conexiones se hacen
+ a través de un pool de conexiones JDBC, que tambén tenemos que configurar.
+ La distribución de Hibernate contiene muchas herramientas de pooling de conexiones
+ JDBC de código abierto, pero para este tutorial usaremos el pool de conexiones
+ prefabricado dentro de Hibernate. Observa que tienes que copiar la biblioteca requerida
+ en tu classpath y usar diferentes configuraciones de pooling de conexiones si quieres
+ usar un software de pooling JDBC de terceros de calidad de producción.
+ </para>
+
+ <para>
+ Para la configuración de Hibernate, podemos usar un fichero
+ <literal>hibernate.properties</literal> simple, un fichero <literal>hibernate.cfg.xml</literal>
+ ligeramente más sofisticado, o incluso una configuración completamente
+ programática. La mayoría de los usuarios prefieren el fichero de
+ configuración XML:
+ </para>
+
+ <programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+ "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+ <session-factory>
+
+ <!-- Database connection settings -->
+ <property name="connection.driver_class">org.hsqldb.jdbcDriver</property>
+ <property name="connection.url">jdbc:hsqldb:data/tutorial</property>
+ <property name="connection.username">sa</property>
+ <property name="connection.password"></property>
+
+ <!-- JDBC connection pool (use the built-in) -->
+ <property name="connection.pool_size">1</property>
+
+ <!-- SQL dialect -->
+ <property name="dialect">org.hibernate.dialect.HSQLDialect</property>
+
+ <!-- Echo all executed SQL to stdout -->
+ <property name="show_sql">true</property>
+
+ <!-- Drop and re-create the database schema on startup -->
+ <property name="hbm2ddl.auto">create</property>
+
+ <mapping resource="Event.hbm.xml"/>
+
+ </session-factory>
+
+</hibernate-configuration>]]></programlisting>
+
+ <para>
+ Observa que esta configuración XML usa un DTD diferente.
+ Configuramos la <literal>SessionFactory</literal> de Hibernate, una
+ fábrica global responsable de una base de datos en particular.
+ Si tienes varias bases de datos, usa varias configuraciones
+ <literal><session-factory></literal> , usualmente en varios
+ ficheros de configuración (para un arranque más fácil).
+ </para>
+
+ <para>
+ Los primeros cuatro elementos <literal>property</literal> contienen la configuración
+ necesaria para la conexión JDBC. El elemento de dialecto <literal>property</literal>
+ especifica la variante de SQL en particular que genera Hibernate. La opción
+ <literal>hbm2ddl.auto</literal> activa la generación automática de esquemas
+ de base de datos, directamente en la base de datos. Esto, por supuesto, puede desactivarse
+ (quitando la opción config) o redirigido a un fichero con la ayuda de la tarea
+ de Ant <literal>SchemaExport</literal>. Finalmente, agregamos el(los) fichero(s) de mapeo
+ para clases persistentes.
+ </para>
+
+ <para>
+ Copia este fichero dentro del directorio de código fuente, de modo que
+ termine ubicado en la raiíz del classpath. Hibernate busca automáticamente
+ un fichero llamado <literal>hibernate.cfg.xml</literal> en la raíz del classpath
+ al arrancar.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-firstapp-ant">
+ <title>Construyendo con Ant</title>
+
+ <para>
+ Construiremos ahora el tutorial con Ant. Necesitarás tener Ant instalado.
+ Obténlo de <ulink url="http://ant.apache.org/bindownload.cgi">Página
+ de descarga de Ant</ulink>. No se cubrirá aquí cómo instalar Ant.
+ Por favor refiérete al <ulink url="http://ant.apache.org/manual/index.html">
+ Manual de Ant</ulink>. Después que hayas instalado Ant, podemos comenzar a
+ crear el buildfile. Será llamado <literal>build.xml</literal> y colocado
+ directamente en el directorio de desarrollo.
+ </para>
+
+ <note>
+ <title>Reparar Ant</title>
+ <para>
+ Observa que la distribución de Ant está por defecto rota
+ (como se describe en el FAQ de Ant) y tiene que ser reparado por ti,
+ por ejemplo, si quisieras usar JUnit desde dentro de tu fichero de construcción.
+ Para hacer que funcione la tarea de JUnit (no lo necesitaremos en este tutorial),
+ copia junit.jar a <literal>ANT_HOME/lib</literal> o quita el trozo de plugin
+ <literal>ANT_HOME/lib/ant-junit.jar</literal>.
+ </para>
+ </note>
+
+ <para>
+ Un fichero de construcción básico se ve como esto:
+ </para>
+
+ <programlisting><![CDATA[<project name="hibernate-tutorial" default="compile">
+
+ <property name="sourcedir" value="${basedir}/src"/>
+ <property name="targetdir" value="${basedir}/bin"/>
+ <property name="librarydir" value="${basedir}/lib"/>
+
+ <path id="libraries">
+ <fileset dir="${librarydir}">
+ <include name="*.jar"/>
+ </fileset>
+ </path>
+
+ <target name="clean">
+ <delete dir="${targetdir}"/>
+ <mkdir dir="${targetdir}"/>
+ </target>
+
+ <target name="compile" depends="clean, copy-resources">
+ <javac srcdir="${sourcedir}"
+ destdir="${targetdir}"
+ classpathref="libraries"/>
+ </target>
+
+ <target name="copy-resources">
+ <copy todir="${targetdir}">
+ <fileset dir="${sourcedir}">
+ <exclude name="**/*.java"/>
+ </fileset>
+ </copy>
+ </target>
+
+</project>]]></programlisting>
+
+ <para>
+ Esto dirá a Ant que agregue todos los ficheros en el directorio lib que terminen con
+ <literal>.jar</literal> al classpath usado para la compilación. También copiará
+ todos los ficheros que no sean código Java al directorio objetivo, por ejemplo,
+ ficheros de configuración y mapeos de Hibernate. Si ahora corres Ant, debes obtener
+ esta salida:
+ </para>
+
+ <programlisting><![CDATA[C:\hibernateTutorial\>ant
+Buildfile: build.xml
+
+copy-resources:
+ [copy] Copying 2 files to C:\hibernateTutorial\bin
+
+compile:
+ [javac] Compiling 1 source file to C:\hibernateTutorial\bin
+
+BUILD SUCCESSFUL
+Total time: 1 second ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="tutorial-firstapp-helpers">
+ <title>Arranque y ayudantes</title>
+
+ <para>
+ Es momento de cargar y almacenar algunos objetos <literal>Event</literal>,
+ pero primero tenemos que completar la configuración de algún
+ código de infraestructura. Tenemos que arrancar Hibernate. Este
+ arranque incluye construir un objeto <literal>SessionFactory</literal> global
+ y almacenarlo en algún sitio de fácil acceso en el código
+ de aplicación. Una <literal>SessionFactory</literal> puede abrir nuevas
+ <literal>Session</literal>'s. Una <literal>Session</literal> representa un unidad
+ de trabajo mono-hebra. La <literal>SessionFactory</literal> es un objeto global
+ seguro entre hebras, instanciado una sola vez.
+ </para>
+
+ <para>
+ Crearemos una clase de ayuda <literal>HibernateUtil</literal> que cuide del
+ arranque y haga conveniente el manejo de <literal>Session</literal>.
+ El así llamado patrón <emphasis>Sesión de Hebra Local
+ (ThreadLocal Session)</emphasis> es útil aquí; mantenemos la unidad
+ de trabajo actual asociada a la hebra actual. Echemos una mirada a la implementación:
+ </para>
+
+ <programlisting><![CDATA[import org.hibernate.*;
+import org.hibernate.cfg.*;
+
+public class HibernateUtil {
+
+ public static final SessionFactory sessionFactory;
+
+ static {
+ try {
+ // Create the SessionFactory from hibernate.cfg.xml
+ sessionFactory = new Configuration().configure().buildSessionFactory();
+ } catch (Throwable ex) {
+ // Make sure you log the exception, as it might be swallowed
+ System.err.println("Initial SessionFactory creation failed." + ex);
+ throw new ExceptionInInitializerError(ex);
+ }
+ }
+
+ public static final ThreadLocal session = new ThreadLocal();
+
+ public static Session currentSession() throws HibernateException {
+ Session s = (Session) session.get();
+ // Open a new Session, if this thread has none yet
+ if (s == null) {
+ s = sessionFactory.openSession();
+ // Store it in the ThreadLocal variable
+ session.set(s);
+ }
+ return s;
+ }
+
+ public static void closeSession() throws HibernateException {
+ Session s = (Session) session.get();
+ if (s != null)
+ s.close();
+ session.set(null);
+ }
+}]]></programlisting>
+
+ <para>
+ Esta clase no ólo produce la <literal>SessionFactory</literal> global en
+ su inicializador static (llamado sólo una vez por la JVM al cargar la clase),
+ sino que también tiene una variable <literal>ThreadLocal</literal> para
+ tener la <literal>Session</literal> para la hebra actual. No importa cuándo
+ llames a <literal>HibernateUtil.currentSession()</literal>, siempre devolverá
+ la misma unidad de trabajo de Hibernate en la misma hebra. Una llamada a
+ <literal>HibernateUtil.closeSession()</literal> termina la unidad de trabajo actualmente
+ asociada a la hebra.
+ </para>
+
+ <para>
+ Asegúrate de entender el concepto Java de una variable local a una hebra antes
+ de usar esta ayuda. Una clase <literal>HibernateUtil</literal> más potente puede
+ encontrarse en <literal>CaveatEmptor</literal>, http://caveatemptor.hibernate.org/,
+ así como en el libro "Java Persistence with Hibernate". Observa que esta clase no es necesaria
+ si despliegas Hibernate en un servidor de aplicaciones J2EE: una <literal>Session</literal>
+ será automáticamente ligada a la transacción JTA actual, y puedes
+ buscar la <literal>SessionFactory</literal> a través de JNDI. Si usas JBoss AS,
+ Hibernate puede ser desplegado como un servicio de sistema manejado y automáticamente
+ ligará la <literal>SessionFactory</literal> a un nombre JNDI.
+ </para>
+
+ <para>
+ Coloca <literal>HibernateUtil.java</literal> en el directorio de fuentes de desarrollo,
+ junto a <literal>Event.java</literal>:
+ </para>
+
+ <programlisting><![CDATA[.
++lib
+ <Hibernate and third-party libraries>
++src
+ Event.java
+ Event.hbm.xml
+ HibernateUtil.java
+ hibernate.cfg.xml
++data
+build.xml]]></programlisting>
+
+ <para>
+ Esto también debe compilar sin problemas. Finalmente necesitamos configurar
+ un sistema de logging (registro). Hibernate usa commons logging y te deja la elección
+ entre Log4J y logging de JDK 1.4. La mayoría de los desarrolladores prefieren
+ Log4J: copia <literal>log4j.properties</literal> de la distribución de Hibernate
+ (está en el directorio <literal>etc/</literal>) a tu directorio <literal>src</literal>,
+ junto a <literal>hibernate.cfg.xml</literal>. Echa una mirada a la configuración de
+ ejemplo y cambia los ajustes si te gusta tener una salida más verborrágica.
+ Por defecto, sólo se muestra el mensaje de arranque de Hibernate en la salida.
+ </para>
+
+ <para>
+ La infraestructura del tutorial está completa, y estamos listos para hacer
+ algún trabajo real con Hibernate.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-firstapp-workingpersistence">
+ <title>Cargando y almacenando objetos</title>
+
+ <para>
+ Finalmente, podemos usar Hibernate para cargar y almacenar objetos.
+ Escribimos una clase <literal>EventManager</literal> con un método
+ <literal>main()</literal>:
+ </para>
+
+ <programlisting><![CDATA[import org.hibernate.Transaction;
+import org.hibernate.Session;
+
+import java.util.Date;
+
+public class EventManager {
+
+ public static void main(String[] args) {
+ EventManager mgr = new EventManager();
+
+ if (args[0].equals("store")) {
+ mgr.createAndStoreEvent("My Event", new Date());
+ }
+
+ HibernateUtil.sessionFactory.close();
+ }
+
+}]]></programlisting>
+
+ <para>
+ Leemos algunos argumentos de la línea de comandos, y si el primer
+ argumento es "store", creamos y almacenamos un nuevo Event:
+ </para>
+
+ <programlisting><![CDATA[private void createAndStoreEvent(String title, Date theDate) {
+ Session session = HibernateUtil.currentSession();
+ Transaction tx = session.beginTransaction();
+
+ Event theEvent = new Event();
+ theEvent.setTitle(title);
+ theEvent.setDate(theDate);
+
+ session.save(theEvent);
+
+ tx.commit();
+ HibernateUtil.closeSession();
+}]]></programlisting>
+
+ <para>
+ Creamos un nuevo objeto <literal>Event</literal>, y se lo damos a Hibernate.
+ Hibernate cuida ahora del SQL y ejecuta <literal>INSERT</literal>s en la base
+ de datos. Echemos una mirada al código de manejo de <literal>Session</literal>
+ y <literal>Transaction</literal> antes de ejecutar esto.
+ </para>
+
+ <para>
+ Una <literal>Session</literal> es una sola unidad de trabajo. Podría sorprenderte
+ que tengamos una API adicional, <literal>Transaction</literal>. Esto implica que una unidad
+ de trabajo puede ser "más larga" que una sola transacción de base de datos;
+ imagina una unidad de trabajo que se abarca varios ciclos petición/respuesta HTTP
+ (por ejemplo, un diálogo asistente) en una aplicación web. Separar las
+ transacciones de base de datos de "las unidades de trabajo de la aplicación desde
+ el punto de vista del usuario" es uno de los conceptos básicos de diseño de
+ Hibernate. Llamamos una unidad de trabajo larga <emphasis>Transacción de
+ Aplicación</emphasis>, usualmente encapsulando varias transacciones de base de
+ datos más cortas. Por ahora mantendremos las cosas simples y asumiremos una
+ granularidad uno-a-uno entre una <literal>Session</literal> y una <literal>Transaction</literal>.
+ </para>
+
+ <para>
+ ¿Qué es lo que hacen <literal>Transaction.begin()</literal> y <literal>commit()</literal>?
+ ¿Dónde está el rollback en caso que algo vaya mal? La API de <literal>Transaction</literal>
+ de Hibernate es opcional realmente, pero la usamos por conveniencia y portabilidad. Si manejases
+ la transacción de base de datos por ti mismo (por ejemplo, llamando a
+ <literal>session.connection.commit()</literal>), ligarías el código a un entorno
+ de despliegue particular, en este JDBC directo no manejado. Estableciendo la fábrica
+ de <literal>Transaction</literal> en tu configuración de Hibernate puedes desplegar
+ tu capa de persistencia en cualquier sitio. Echa una mirada al <xref linkend="transactions"/>
+ para más información sobre manejo y demarcación de transacciones.
+ Hemos saltado también cualquier manejo de excepciones y rollback en este ejemplo.
+ </para>
+
+ <para>
+ Para ejecutar la primera rutina tenemos que agregar un objetivo llamable al fichero
+ de construcción de Ant:
+ </para>
+
+ <programlisting><![CDATA[<target name="run" depends="compile">
+ <java fork="true" classname="EventManager" classpathref="libraries">
+ <classpath path="${targetdir}"/>
+ <arg value="${action}"/>
+ </java>
+</target>]]></programlisting>
+
+ <para>
+ El valor del argumento <literal>action</literal> es establecido por línea de
+ comandos al llamar al objetivo:
+ </para>
+
+ <programlisting><![CDATA[C:\hibernateTutorial\>ant run -Daction=store]]></programlisting>
+
+ <para>
+ Debes ver, después de la compilación, a Hibernate arrancando y, dependiendo
+ de tu configuración mucha salida de registro (log). Al final encontrarás
+ la siguiente línea:
+ </para>
+
+ <programlisting><![CDATA[[java] Hibernate: insert into EVENTS (EVENT_DATE, title, EVENT_ID) values (?, ?, ?)]]></programlisting>
+
+ <para>
+ Esta es la <literal>INSERT</literal> ejecutada por Hibernate, los signos de preguntas
+ representan parámetros de ligado JDBC. Para ver los valores ligados como
+ argumentos, o para reducir la verborragia del registro, chequea tu
+ <literal>log4j.properties</literal>.
+ </para>
+
+ <para>
+ Ahora quisiéramos listar acontecimientos almacenados también,
+ así que agregamos una opción al método principal:
+ </para>
+
+ <programlisting><![CDATA[if (args[0].equals("store")) {
+ mgr.createAndStoreEvent("My Event", new Date());
+}
+else if (args[0].equals("list")) {
+ List 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());
+ }
+}]]></programlisting>
+
+ <para>
+ Agregamos también un nuevo método <literal>listEvents()</literal>:
+ </para>
+
+ <programlisting><![CDATA[private List listEvents() {
+ Session session = HibernateUtil.currentSession();
+ Transaction tx = session.beginTransaction();
+
+ List result = session.createQuery("from Event").list();
+
+ tx.commit();
+ session.close();
+
+ return result;
+}]]></programlisting>
+
+ <para>
+ Lo que hacemos aquí es usar una consulta HQL (Lenguaje de Consulta de Hibernate
+ o Hibernate Query Language) para cargar todos los objetos <literal>Event</literal>
+ existentes de la base de datos. Hibernate generará el SQL apropiado, lo enviará
+ a la base de datosy poblará los objetos <literal>Event</literal> con datos.
+ Puedes, por supuesto, crear consultas más complejas con HQL.
+ </para>
+
+ <para>
+ Si ahora llamas a Ant con <literal>-Daction=list</literal>, debes ver los eventos
+ que has almacenado hasta ahora. Puede sorprenderte que esto no funcione, al menos
+ si has seguido este tutorial paso por paso; el resultado siempre estará
+ vacío. La razon de esto es la opción <literal>hbm2ddl.auto</literal>
+ en la configuración de Hibernate: Hibernate recreará la base de datos
+ en cada ejecución. Deshabilítala quitando la opción, y verás
+ resultados en tu listado después que llames a la acción <literal>store</literal>
+ unas cuantas veces. La generación y exportación de esquema es útil
+ mayormente en testeo unitario.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="tutorial-associations">
+ <title>Part 2 - Mapeando asociaciones</title>
+
+ <para>
+ Hemos mapeado un clase de entidad persistente a una tabla. Construyamos sobre esto y agreguemos
+ algunas asociaciones de clase. Primero agregaremos personas a nuestra aplicación,
+ y almacenaremos una lista de eventos en las que participan.
+ </para>
+
+ <sect2 id="tutorial-associations-mappinguser">
+ <title>Mapeando la clase Person</title>
+
+ <para>
+ El primer corte de la clase <literal>Person</literal> es simple:
+ </para>
+
+ <programlisting><![CDATA[public class Person {
+
+ private Long id;
+ private int age;
+ private String firstname;
+ private String lastname;
+
+ Person() {}
+
+ // Accessor methods for all properties, private setter for 'id'
+
+}]]></programlisting>
+
+ <para>
+ Crea un fichero de mapeo llamado <literal>Person.hbm.xml</literal>:
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+
+ <class name="Person" table="PERSON">
+ <id name="id" column="PERSON_ID">
+ <generator class="increment"/>
+ </id>
+ <property name="age"/>
+ <property name="firstname"/>
+ <property name="lastname"/>
+ </class>
+
+</hibernate-mapping>]]></programlisting>
+
+ <para>
+ Finalmente, agrega el nuevo mapeo a la configuración de Hibernate:
+ </para>
+
+ <programlisting><![CDATA[ <mapping resource="Event.hbm.xml"/>
+ <mapping resource="Person.hbm.xml"/>
+]]></programlisting>
+
+ <para>
+ Crearemos ahora una asociación entre estas dos entidades. Obviamente,
+ las personas pueden participar en eventos, y los eventos tienen participantes.
+ Las cuestiones de diseño con que tenemos que tratar son: direccionalidad,
+ multiplicidad y comportamiento de colección.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-associations-unidirset">
+ <title>Una asociación unidireccional basada en Set</title>
+
+ <para>
+ Agregaremos una colección de eventos a la clase <literal>Person</literal>.
+ De esta forma podemos navegar facilmente a los eventos de una persona en particular,
+ sin ejecutar una consulta explícita, llamando a <literal>aPerson.getEvents()</literal>.
+ Usamos una colección Java, un <literal>Set</literal>, porque la colección no
+ contendrá elementos duplicados y el ordenamiento no nos es relevante.
+ </para>
+
+ <para>
+ Hasta ahora hemos diseñado asociaciones unidireccionales multivaluadas, implementadas con un
+ <literal>Set</literal>. Escribamos el código para esto en las clases Java y luego lo
+ mapeemos:
+ </para>
+
+ <programlisting><![CDATA[public class Person {
+
+ private Set events = new HashSet();
+
+ public Set getEvents() {
+ return events;
+ }
+
+ public void setEvents(Set events) {
+ this.events = events;
+ }
+}]]></programlisting>
+
+ <para>
+ Antes que mapeemos esta asociación, piensa sobre el otro lado. Claramente, podemos
+ mantener esto solamente unidireccional. O podemos crear otra colección en el
+ <literal>Event</literal>, si queremos ser capaces de navegarlos bidireccionalmente;
+ por ejemplo, <literal>anEvent.getParticipants()</literal>. Esta es una elección
+ de diseño que recae en ti, pero lo que está claro de esta discusión
+ es la multiplicidad de la asociación: "multi" valuada a ambos lados, llamamos a esto
+ una asociación <emphasis>muchos-a-muchos</emphasis>. Por lo tanto, usamos un mapeo
+ many-to-many de Hibernate:
+ </para>
+
+ <programlisting><![CDATA[<class name="Person" table="PERSON">
+ <id name="id" column="PERSON_ID">
+ <generator class="increment"/>
+ </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="Event"/>
+ </set>
+
+</class>]]></programlisting>
+
+ <para>
+ Hibernate soporta todo tipo de mapeos de colección, siendo el más común
+ un <literal><set></literal>. Para una asociación muchos-a-muchos (o relación
+ de entidad <emphasis>n:m</emphasis>), se necesita una tabla de asociación. Cada fila en esta
+ tabla representa un enlace entre una persona y un evento. Esta tabla se configura con el atributo
+ <literal>table</literal> del elemento <literal>set</literal>. El nombre de la columna identificadora
+ en la asociación, para el lado de la persona, se define con el elemento
+ <literal><key></literal>. El nombre de columna para el lado del evento se define con el atributo
+ <literal>column</literal> del <literal><many-to-many></literal>. También tienes que decirle
+ a Hibernate la clase de los objetos en tu colección (correcto: la clase del otro lado de la
+ colección de referencias).
+ </para>
+
+ <para>
+ El esquema de base de datos para este mapeo es, por lo tanto:
+ </para>
+
+ <programlisting><![CDATA[
+ _____________ __________________
+ | | | | _____________
+ | EVENTS | | PERSON_EVENT | | |
+ |_____________| |__________________| | PERSON |
+ | | | | |_____________|
+ | *EVENT_ID | <--> | *EVENT_ID | | |
+ | EVENT_DATE | | *PERSON_ID | <--> | *PERSON_ID |
+ | TITLE | |__________________| | AGE |
+ |_____________| | FIRSTNAME |
+ | LASTNAME |
+ |_____________|
+ ]]></programlisting>
+
+ </sect2>
+
+ <sect2 id="tutorial-associations-working">
+ <title>Trabajando la asociación</title>
+
+ <para>
+ Traigamos alguna gente y eventos juntos en un nuevo método en
+ <literal>EventManager</literal>:
+ </para>
+
+ <programlisting><![CDATA[private void addPersonToEvent(Long personId, Long eventId) {
+ Session session = HibernateUtil.currentSession();
+ Transaction tx = session.beginTransaction();
+
+ Person aPerson = (Person) session.load(Person.class, personId);
+ Event anEvent = (Event) session.load(Event.class, eventId);
+
+ aPerson.getEvents().add(anEvent);
+
+ tx.commit();
+ HibernateUtil.closeSession();
+}]]></programlisting>
+
+ <para>
+ Después de cargar una <literal>Person</literal> y un <literal>Event</literal>, simplemente
+ modifica la colección usando sus métodos normales. Como puedes ver, no hay una llamada
+ explícita a <literal>update()</literal> o <literal>save()</literal>. Hibernate detecta
+ automáticamente que la colección ha sido modificada y necesita ser salvada. Esto
+ es llamado <emphasis>chequeo sucio automótico (automatic dirty checking)</emphasis>, y
+ también puedes intentarlo modificando el nombre de la propiedad de fecha de cualquiera de tus
+ objetos. Mientras estén en estado <emphasis>persistente</emphasis>, esto es, ligados a una
+ <literal>Session</literal> de Hibernate particular (es decir, justo han sido cargados o almacenados
+ en una unidad de trabajo), Hibernate monitoriza cualquier cambio y ejecuta SQL en estilo
+ escribe-por-detrás. El proceso de sincronización del estado de memoria con la base
+ de datos, usualmente sólo al final de una unidad de trabajo,
+ es llamado <emphasis>limpieza (flushing)</emphasis>.
+ </para>
+
+ <para>
+ Podrías, por supuesto, cargar persona y evento en unidades de trabajo diferentes. O
+ modificas un objeto fuera de una <literal>Session</literal>, cuando no está en estado
+ persistente (si antes era persistente llamamos a este estado <emphasis>separado (detached)
+ </emphasis>). En código (no muy realista), esto se vería como sigue:
+ </para>
+
+ <programlisting><![CDATA[ private void addPersonToEvent(Long personId, Long eventId) {
+
+ Session session = HibernateUtil.currentSession();
+ Transaction tx = session.beginTransaction();
+
+ Person aPerson = (Person) session.load(Person.class, personId);
+ Event anEvent = (Event) session.load(Event.class, eventId);
+
+ tx.commit();
+ HibernateUtil.closeSession();
+
+ aPerson.getEvents().add(anEvent); // aPerson is detached
+
+ Session session2 = HibernateUtil.currentSession();
+ Transaction tx2 = session.beginTransaction();
+
+ session2.update(aPerson); // Reattachment of aPerson
+
+ tx2.commit();
+ HibernateUtil.closeSession();
+ }
+]]></programlisting>
+
+ <para>
+ La llamada a <literal>update</literal> hace a un objeto persistente de nuevo, podrías
+ decir que la liga a una nueva unidad de trabajo, de modo que cualquier modificación que
+ le hagas mientras esté separado puede ser salvada a base de datos.
+ </para>
+
+ <para>
+ Bueno, esto no es muy usado en nuestra situación actual, pero es un concepto
+ importante que puedes diseñar en tu propia aplicación. Por ahora, completa
+ este ejercicio agregando una nueva acción al método main de
+ <literal>EventManager</literal> y llámala desde la línea de comandos.
+ Si necesitas los identificadores de una persona o evento, el método
+ <literal>save()</literal> los devuelve.
+ </para>
+
+ <para>
+ Esto fue un ejemplo de una asociación entre dos clases igualmente importantes, dos entidades.
+ Como se ha mencionado anteriormente, hay otras clases y tipos en un modelo típico,
+ usualmente "menos importantes". Algunos ya los habrás visto, como un <literal>int</literal>
+ o un <literal>String</literal>. Llamamos a estas clases <emphasis>tipos de valor (value types)</emphasis>,
+ y sus instancias <emphasis>dependen</emphasis> de una entidad en particular. Las instancias de estos
+ tipos no tienen su propia identidad, ni son compartidas entre entidades (dos personas no referencian
+ el mismo objeto <literal>firstname</literal>, incluso si tuvieran el mismo primer nombre). Por supuesto,
+ los tipos de valor no sólo pueden encontrarse en el JDK (de hecho, en una aplicación
+ Hibernate todas las clases del JDK son consideradas tipos de valor), sino que además puedes
+ escribir por ti mismo clases dependientes, por ejemplo, <literal>Address</literal> o
+ <literal>MonetaryAmount</literal>.
+ </para>
+
+ <para>
+ También puedes diseñar una colección de tipos de valor. Esto es conceptualmente
+ muy diferente de una colección de referencias a otras entidades, pero se ve casi lo mismo en
+ Java.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-associations-valuecollections">
+ <title>Colección de valores</title>
+
+ <para>
+ Agregamos una colección de objetos tipificados en valor a la entidad <literal>Person</literal>.
+ Queremos almacenar direcciones de email, de modo que el tipo que usamos es <literal>String</literal>,
+ y la colección es nuevamente un <literal>Set</literal>:
+ </para>
+ <programlisting><![CDATA[private Set emailAddresses = new HashSet();
+
+public Set getEmailAddresses() {
+ return emailAddresses;
+}
+
+public void setEmailAddresses(Set emailAddresses) {
+ this.emailAddresses = emailAddresses;
+}]]></programlisting>
+
+ <para>
+ El mapeo de este <literal>Set</literal>:
+ </para>
+
+ <programlisting><![CDATA[<set name="emailAddresses" table="PERSON_EMAIL_ADDR">
+ <key column="PERSON_ID"/>
+ <element type="string" column="EMAIL_ADDR"/>
+</set>]]></programlisting>
+
+ <para>
+ La diferencia comparada con el mapeo anterior es la parte <literal>element</literal>, que le dice
+ a Hibernate que la colección no contiene referencias a otra entidad, sino una colección
+ de elementos de tipo <literal>String</literal> (el nombre en minúsculas te dice que es un
+ tipo/conversor de mapeo de Hibernate). Una vez más, el atributo <literal>table</literal> del
+ elemento <literal>set</literal> determina el nombre de la tabla para la colección. El elemento
+ <literal>key</literal> define el nombre de la columna clave foránea en la tabla de colección.
+ El atributo <literal>column</literal> en el elemento <literal>element</literal> define el nombre de
+ columna donde realmente serán almacenados los valores <literal>String</literal>.
+ </para>
+
+ <para>
+ Echa una mirada al esquema actualizado:
+ </para>
+
+ <programlisting><![CDATA[
+ _____________ __________________
+ | | | | _____________
+ | EVENTS | | PERSON_EVENT | | | ___________________
+ |_____________| |__________________| | PERSON | | |
+ | | | | |_____________| | PERSON_EMAIL_ADDR |
+ | *EVENT_ID | <--> | *EVENT_ID | | | |___________________|
+ | EVENT_DATE | | *PERSON_ID | <--> | *PERSON_ID | <--> | *PERSON_ID |
+ | TITLE | |__________________| | AGE | | *EMAIL_ADDR |
+ |_____________| | FIRSTNAME | |___________________|
+ | LASTNAME |
+ |_____________|
+ ]]></programlisting>
+
+ <para>
+ Puedes ver que la clave primaria de la tabla de colección es de hecho una clave
+ compuesta, usando ambas columnas. Esto implica también que no pueden haber
+ direcciones de email duplicadas por persona, que es exactamente la semántica
+ que necesitamos para un conjunto en Java.
+ </para>
+
+ <para>
+ Puedes ahora intentar y agregar elementos a esta colección, al igual que
+ hicimos antes enlazando personas y eventos. Es el mismo código en Java.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-associations-bidirectional">
+ <title>Asociaciones bidireccionales</title>
+
+ <para>
+ A continuacion vamos a mapear una asociación bidireccional, haciendo que la
+ asociación entre persona y evento funcione desde ambos lados en Java. Por supuesto,
+ el esquema de base de datos no cambia; todavía necesitamos multiplicidad muchos-a-muchos.
+ Una base de datos relacional es más flexible que un lenguaje de programación
+ de red, así que no necesita nada parecido a una dirección de navegación;
+ los datos pueden ser vistos y recuperados en cualquier forma posible.
+ </para>
+
+ <para>
+ Primero agrega una colección de participantes a la clase de eventos
+ <literal>Event</literal>:
+ </para>
+
+ <programlisting><![CDATA[private Set participants = new HashSet();
+
+public Set getParticipants() {
+ return participants;
+}
+
+public void setParticipants(Set participants) {
+ this.participants = participants;
+}]]></programlisting>
+
+ <para>
+ Ahora mapea este lado de la asociación también, en
+ <literal>Event.hbm.xml</literal>.
+ </para>
+
+ <programlisting><![CDATA[<set name="participants" table="PERSON_EVENT" inverse="true">
+ <key column="EVENT_ID"/>
+ <many-to-many column="PERSON_ID" class="Person"/>
+</set>]]></programlisting>
+
+ <para>
+ Como ves, estos son mapeos normales de <literal>set</literal> en ambos documentos de
+ mapeo. Nota que los nombres de columnas en <literal>key</literal> y
+ <literal>many-to-many</literal> fueron permutados en ambos documentos de mapeo. Aquí la
+ adición más importante es el atributo <literal>inverse="true"</literal> en el
+ elemento <literal>set</literal> del mapeo de colección de <literal>Event</literal>.
+ </para>
+
+ <para>
+ Lo que esto significa es que Hibernate debe tomar el otro lado - la clase <literal>Person</literal> -
+ cuando necesite descubrir información sobre el enlace entre las dos. Esto será mucho
+ más fácil de entender una vez que veas cómo se crea el enlace bidireccional
+ entre nuestras dos entidades.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-associations-usingbidir">
+ <title>Trabajando enlaces bidireccionales</title>
+
+ <para>
+ Primero, ten en mente que Hhibernate no afecta la semántica normal de Java. ¿Cómo
+ hemos creado un enlace entre una <literal>Person</literal> y un <literal>Event</literal> en el
+ ejemplo unidireccional? Hemos agregado una instancia de <literal>Event</literal> a la colección
+ de referencias de eventos de una instancia de <literal>Person</literal>. De modo que, obviamente,
+ si queremos que este enlace funcione bidireccionalmente, tenemos que hacer lo mismo del otro lado,
+ agregando una referencia a <literal>Person</literal> a la colección en un <literal>Event</literal>.
+ Este "establecer el enlace a ambos lados" es absolutamente necesario y nunca debes olvidar hacerlo.
+ </para>
+
+ <para>
+ Muchos desarrolladores programan a la defensiva y crean métodos de
+ manejo de un enlace para establecer correctamente ambos lados, por ejemplo
+ en <literal>Person</literal>:
+ </para>
+
+ <programlisting><![CDATA[protected Set getEvents() {
+ return events;
+}
+
+protected void setEvents(Set events) {
+ this.events = events;
+}
+
+public void addToEvent(Event event) {
+ this.getEvents().add(event);
+ event.getParticipants().add(this);
+}
+
+public void removeFromEvent(Event event) {
+ this.getEvents().remove(event);
+ event.getParticipants().remove(this);
+}]]></programlisting>
+
+ <para>
+ Nota que los métodos get y set para esta colección son ahora protegidos. Esto le
+ permite a clases en el mismo paquete y a subclases acceder aún a los métodos, pero
+ previene a cualquier otro de ensuciarse con la colección directamente (bueno, casi).
+ Probablemente debas hacer lo mismo con la colección al otro lado.
+ </para>
+
+ <para>
+ Y ¿qué del atributo de mapeo <literal>inverse</literal>? Para ti, y para Java, un enlace
+ bidireccional es simplemente cuestión de establecer correctamente las referencias a ambos
+ lados. Hibernate, sin embargo, no tiene suficiente información para arreglar correctamente
+ sentencias <literal>INSERT</literal> y <literal>UPDATE</literal> de SQL (para evitar violación
+ de restricciones), y necesita alguna ayuda para manejar asociaciones bidireccionales apropiadamente.
+ El hacer un lado de la asociación <literal>inverse</literal> le dice a Hibernate que basicamente
+ lo ignore, que lo considere un <emphasis>espejo</emphasis> del otro lado. Esto es todo lo necesario para
+ que Hibernate resuelva todas las incidencias al transformar un modelo de navegación direccional a
+ un esquema SQL de base de datos. Las reglas que tienes que recordar son directas: Todas las asociaciones
+ bidireccionales necesitan uno de los lados como <literal>inverse</literal>. En una asociación
+ uno-a-muchos debe ser el lado-de-muchos. En una asociación muchos-a-muchos, puedes tomar cualquier
+ lado, no hay diferencia.
+ </para>
+<!--
+ <para>
+ In the next section we integrate Hibernate with Tomcat and WebWork - the <literal>EventManager</literal>
+ doesn't scale anymore with our growing application.
+ </para>
+-->
+ </sect2>
+ </sect1>
+
+ <sect1 id="tutorial-summary">
+ <title>Summary</title>
+
+ <para>
+ Este tutorial cubrió los fundamentos de escribir una simple aplicación independiente
+ de Hibernate.
+ </para>
+
+ <para>
+ Si ya te sientes confidente con Hibernate, continúa navegando a través de la
+ tabla de contenidos de la documentación de referencia para los temas que encuentres
+ interesantes. Los más consultados son procesamiento transaccional (<xref linkend="transactions"/>),
+ rendimiento de recuperación (<xref linkend="performance"/>), o el uso de la API
+ (<xref linkend="objectstate"/>) y las funcionalidades de consulta (<xref linkend="objectstate-querying"/>).
+ </para>
+
+ <para>
+ No olvides chequear el sitio web de Hibernate por más (especializados) tutoriales.
+ </para>
+
+ </sect1>
+
+</chapter>
\ No newline at end of file
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/content/xml.xml (from rev 12794, core/trunk/documentation/manual/es-ES/src/main/docbook/modules/xml.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/xml.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/xml.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,282 @@
+<chapter id="xml">
+ <title>Mapeo XML</title>
+
+ <para><emphasis>
+ Nota que esta es una funcionalidad experimental en Hibernate 3.0 y está
+ bajo un desarrollo extremadamente activo.
+ </emphasis></para>
+
+ <sect1 id="xml-intro" revision="1">
+ <title>Trabajando con datos XML</title>
+
+ <para>
+ Hibernate te permite trabajar con datos XML persistentes en casi la misma forma
+ que trabajas con POJOs persistentes. Un árbol XML analizado (parsed) puede ser
+ pensado como sólo otra forma de representar los datos relacionales a nivel de objetos,
+ en vez de POJOs.
+ </para>
+
+ <para>
+ Hibernate soporta dom4j como API para manipular árboles XML. Puedes escribir
+ consultas que traigan árboles dom4j de la base de datos y tener cualquier modificación
+ que hagas al árbol sincronizada automáticamente a la base de datos. Puedes incluso tomar
+ un documento XML, analizarlo usando dom4j, y escribirlo a la base de datos con cualquiera
+ de las operaciones básicas de Hibernate: <literal>persist(), saveOrUpdate(), merge(),
+ delete(), replicate()</literal> (la fusión no está aún soportada).
+ </para>
+
+ <para>
+ Esta funcionalidad tiene muchas aplicaciones incluyendo la importación/exportación de datos,
+ externalización de datos de entidad vía JMS o SOAP y reportes basados en XSLT.
+ </para>
+
+ <para>
+ Un solo mapeo puede ser usado para mapear simultáneamente las propiedades de una clase y los nodos de un
+ documento XML a la base de datos, o, si no hay ninguna clase a mapear, puede ser usado para mapear sólo
+ el XML.
+ </para>
+
+ <sect2 id="xml-intro-mapping">
+ <title>Especificando los mapeos de XML y de clase juntos</title>
+
+ <para>
+ He aquí un ejemplo de mapear un POJO y XML simultáneamente:
+ </para>
+
+ <programlisting><![CDATA[<class name="Account"
+ table="ACCOUNTS"
+ node="account">
+
+ <id name="accountId"
+ column="ACCOUNT_ID"
+ node="@id"/>
+
+ <many-to-one name="customer"
+ column="CUSTOMER_ID"
+ node="customer/@id"
+ embed-xml="false"/>
+
+ <property name="balance"
+ column="BALANCE"
+ node="balance"/>
+
+ ...
+
+</class>]]></programlisting>
+ </sect2>
+
+ <sect2 id="xml-onlyxml">
+ <title>Especificando sólo un mapeo XML</title>
+
+ <para>
+ He aquí un ejemplo donde no hay ninguna clase POJO:
+ </para>
+
+ <programlisting><![CDATA[<class entity-name="Account"
+ table="ACCOUNTS"
+ node="account">
+
+ <id name="id"
+ column="ACCOUNT_ID"
+ node="@id"
+ type="string"/>
+
+ <many-to-one name="customerId"
+ column="CUSTOMER_ID"
+ node="customer/@id"
+ embed-xml="false"
+ entity-name="Customer"/>
+
+ <property name="balance"
+ column="BALANCE"
+ node="balance"
+ type="big_decimal"/>
+
+ ...
+
+</class>]]></programlisting>
+
+ <para>
+ Este mapeo te permite acceder a los datos como un árbol dom4j, o como un grafo de pares nombre/valor de
+ propiedad (<literal>Map</literal>s de Java). Los nombres de propiedades son construcciones puramente
+ lógicas a las que se puede hacer referencia en consultas HQL.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="xml-mapping" revision="1">
+ <title>Mapeo de metadatos XML</title>
+
+ <para>
+ Muchos elementos de mapeo de Hibernate aceptan el atributo <literal>node</literal>. Esto te permite espcificar
+ el nombre de un atributo o elemento XML que contenga los datos de la propiedad o entidad. El formato del
+ atributo <literal>node</literal> debe ser uno de los siguientes:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para><literal>"element-name"</literal> - mapea al elemento XML mencionado</para>
+ </listitem>
+ <listitem>
+ <para><literal>"@attribute-name"</literal> - mapea al atributo XML mencionado</para>
+ </listitem>
+ <listitem>
+ <para><literal>"."</literal> - mapea al elemento padre</para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>"element-name/@attribute-name"</literal> -
+ mapea al atributo mencionado del elemento mencionado
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ Para las colecciones y asociaciones monovaluadas, existe un atributo adicional <literal>embed-xml</literal>.
+ Si <literal>embed-xml="true"</literal>, que es el valor por defecto, el árbol XML para la entidad
+ asociada (o colección de tipo de valor) será embebida directamente en el árbol XML para la entidad que
+ posee la asociación. En otro caso, si <literal>embed-xml="false"</literal>, sólo el valor identificador
+ referenciado aparecerá en el XML para asociaciones de punto único y para las colecciones simplemente
+ no aparecerá en absoluto.
+ </para>
+
+ <para>
+ ¡Debes ser cuidadoso de no dejar <literal>embed-xml="true"</literal> para demasiadas asociaciones,
+ ya que XML no trata bien la circularidad!
+ </para>
+
+ <programlisting><![CDATA[<class name="Customer"
+ table="CUSTOMER"
+ node="customer">
+
+ <id name="id"
+ column="CUST_ID"
+ node="@id"/>
+
+ <map name="accounts"
+ node="."
+ embed-xml="true">
+ <key column="CUSTOMER_ID"
+ not-null="true"/>
+ <map-key column="SHORT_DESC"
+ node="@short-desc"
+ type="string"/>
+ <one-to-many entity-name="Account"
+ embed-xml="false"
+ node="account"/>
+ </map>
+
+ <component name="name"
+ node="name">
+ <property name="firstName"
+ node="first-name"/>
+ <property name="initial"
+ node="initial"/>
+ <property name="lastName"
+ node="last-name"/>
+ </component>
+
+ ...
+
+</class>]]></programlisting>
+
+ <para>
+ en este caso, hemos decidido embeber la colección de ids de cuenta, pero no los datos reales de cuenta.
+ La siguiente consulta HQL:
+ </para>
+
+ <programlisting><![CDATA[from Customer c left join fetch c.accounts where c.lastName like :lastName]]></programlisting>
+
+ <para>
+ devolvería conjuntos de datos como estos:
+ </para>
+
+ <programlisting><![CDATA[<customer id="123456789">
+ <account short-desc="Savings">987632567</account>
+ <account short-desc="Credit Card">985612323</account>
+ <name>
+ <first-name>Gavin</first-name>
+ <initial>A</initial>
+ <last-name>King</last-name>
+ </name>
+ ...
+</customer>]]></programlisting>
+
+ <para>
+ Si estableces <literal>embed-xml="true"</literal> en el mapeo <literal><one-to-many></literal>, los datos
+ podrían verse así:
+ </para>
+
+ <programlisting><![CDATA[<customer id="123456789">
+ <account id="987632567" short-desc="Savings">
+ <customer id="123456789"/>
+ <balance>100.29</balance>
+ </account>
+ <account id="985612323" short-desc="Credit Card">
+ <customer id="123456789"/>
+ <balance>-2370.34</balance>
+ </account>
+ <name>
+ <first-name>Gavin</first-name>
+ <initial>A</initial>
+ <last-name>King</last-name>
+ </name>
+ ...
+</customer>]]></programlisting>
+
+ </sect1>
+
+
+ <sect1 id="xml-manipulation" revision="1">
+ <title>Manipulando datos XML</title>
+
+ <para>
+ Vamos a releer y actualizar documentos XML en la aplicación. Hacemos esto obteniendo una sesión dom4j:
+ </para>
+
+ <programlisting><![CDATA[Document doc = ....;
+
+Session session = factory.openSession();
+Session dom4jSession = session.getSession(EntityMode.DOM4J);
+Transaction tx = session.beginTransaction();
+
+List results = dom4jSession
+ .createQuery("from Customer c left join fetch c.accounts where c.lastName like :lastName")
+ .list();
+for ( int i=0; i<results.size(); i++ ) {
+ //add the customer data to the XML document
+ Element customer = (Element) results.get(i);
+ doc.add(customer);
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+ <programlisting><![CDATA[Session session = factory.openSession();
+Session dom4jSession = session.getSession(EntityMode.DOM4J);
+Transaction tx = session.beginTransaction();
+
+Element cust = (Element) dom4jSession.get("Customer", customerId);
+for ( int i=0; i<results.size(); i++ ) {
+ Element customer = (Element) results.get(i);
+ //change the customer name in the XML and database
+ Element name = customer.element("name");
+ name.element("first-name").setText(firstName);
+ name.element("initial").setText(initial);
+ name.element("last-name").setText(lastName);
+}
+
+tx.commit();
+session.close();]]></programlisting>
+
+ <para>
+ Es extremadamente útil combinar esta funcionalidad con la operación <literal>replicate()</literal>
+ de Hibernate para implementar la importación/exportación de datos basada en XML.
+ </para>
+
+ </sect1>
+
+</chapter>
+
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/images/AuthorWork.png (from rev 14074, core/trunk/documentation/manual/fr-FR/src/main/docbook/images/AuthorWork.png)
===================================================================
(Binary files differ)
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/images/AuthorWork.zargo (from rev 14074, core/trunk/documentation/manual/fr-FR/src/main/docbook/images/AuthorWork.zargo)
===================================================================
(Binary files differ)
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/images/CustomerOrderProduct.png (from rev 14074, core/trunk/documentation/manual/fr-FR/src/main/docbook/images/CustomerOrderProduct.png)
===================================================================
(Binary files differ)
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/images/CustomerOrderProduct.zargo (from rev 14074, core/trunk/documentation/manual/fr-FR/src/main/docbook/images/CustomerOrderProduct.zargo)
===================================================================
(Binary files differ)
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/images/EmployerEmployee.png (from rev 14074, core/trunk/documentation/manual/fr-FR/src/main/docbook/images/EmployerEmployee.png)
===================================================================
(Binary files differ)
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/images/EmployerEmployee.zargo (from rev 14074, core/trunk/documentation/manual/fr-FR/src/main/docbook/images/EmployerEmployee.zargo)
===================================================================
(Binary files differ)
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/images/full_cream.png (from rev 14074, core/trunk/documentation/manual/fr-FR/src/main/docbook/images/full_cream.png)
===================================================================
(Binary files differ)
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/images/full_cream.svg (from rev 14074, core/trunk/documentation/manual/fr-FR/src/main/docbook/images/full_cream.svg)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/images/full_cream.svg (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/images/full_cream.svg 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,429 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+ xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="354.331"
+ height="336.614"
+ id="svg1">
+ <defs
+ id="defs3">
+ <linearGradient
+ x1="0"
+ y1="0"
+ x2="1"
+ y2="0"
+ id="linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop128" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop129" />
+ </linearGradient>
+ <linearGradient
+ x1="0"
+ y1="0"
+ x2="1"
+ y2="0"
+ id="linearGradient130"
+ xlink:href="#linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad" />
+ <radialGradient
+ cx="0.5"
+ cy="0.5"
+ fx="0.5"
+ fy="0.5"
+ r="0.5"
+ id="radialGradient131"
+ xlink:href="#linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad" />
+ </defs>
+ <g
+ transform="matrix(0.823795,0,0,0.823795,0.120302,5.25349)"
+ style="font-size:12;"
+ id="g659">
+ <rect
+ width="212.257"
+ height="57.2441"
+ x="17.9576"
+ y="100.132"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect137" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ transform="matrix(0.743454,0,0,0.482981,6.46949,52.2178)"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect132" />
+ </g>
+ <rect
+ width="325.86"
+ height="63.6537"
+ x="17.4083"
+ y="15.194"
+ style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect136" />
+ <rect
+ width="325.86"
+ height="63.6537"
+ x="13.6713"
+ y="12.4966"
+ style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect126" />
+ <g
+ transform="matrix(1.14345,0,0,0.729078,-1.67818,105.325)"
+ style="font-size:12;"
+ id="g164">
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="16.6979"
+ y="222.966"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect138" />
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="14.7335"
+ y="221.002"
+ transform="translate(-1.30962,-1.30992)"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect133" />
+ </g>
+ <text
+ x="170.824753"
+ y="58.402939"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text183">
+ <tspan
+ x="170.824997"
+ y="58.402901"
+ id="tspan360">
+Application</tspan>
+ </text>
+ <text
+ x="178.076340"
+ y="364.281433"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text197">
+ <tspan
+ x="178.076004"
+ y="364.281006"
+ id="tspan421">
+Database</tspan>
+ </text>
+ <text
+ x="68.605331"
+ y="138.524582"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text216">
+ <tspan
+ x="68.605301"
+ y="138.524994"
+ id="tspan384">
+SessionFactory</tspan>
+ </text>
+ <rect
+ width="67.0014"
+ height="101.35"
+ x="196.927"
+ y="89.2389"
+ style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect387" />
+ <rect
+ width="67.0014"
+ height="101.35"
+ x="194.633"
+ y="86.4389"
+ style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect388" />
+ <text
+ x="249.108841"
+ y="173.885559"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text389">
+ <tspan
+ x="249.108994"
+ y="173.886002"
+ id="tspan392">
+Session</tspan>
+ </text>
+ <rect
+ width="73.0355"
+ height="101.35"
+ x="270.995"
+ y="90.0018"
+ style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect395" />
+ <rect
+ width="73.0355"
+ height="101.35"
+ x="267.869"
+ y="87.2018"
+ style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect396" />
+ <text
+ x="328.593658"
+ y="174.715622"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text397">
+ <tspan
+ x="328.593994"
+ y="174.716003"
+ id="tspan563">
+Transaction</tspan>
+ </text>
+ <g
+ transform="matrix(0.29544,0,0,0.397877,9.70533,103.96)"
+ style="font-size:12;"
+ id="g565">
+ <rect
+ width="285.502"
+ height="118.523"
+ x="16.6979"
+ y="99.2053"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect566" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect567" />
+ </g>
+ <text
+ x="25.592752"
+ y="204.497803"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:10;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text568">
+ <tspan
+ x="25.592800"
+ y="204.498001"
+ id="tspan662">
+TransactionFactory</tspan>
+ </text>
+ <g
+ transform="matrix(0.298082,0,0,0.397877,99.6898,103.96)"
+ style="font-size:12;"
+ id="g573">
+ <rect
+ width="285.502"
+ height="118.523"
+ x="16.6979"
+ y="99.2053"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect574" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect575" />
+ </g>
+ <text
+ x="134.030670"
+ y="205.532791"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:10;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text576">
+ <tspan
+ x="134.031006"
+ y="205.533005"
+ id="tspan664">
+ConnectionProvider</tspan>
+ </text>
+ <g
+ transform="matrix(1.14345,0,0,0.729078,-1.67818,38.9539)"
+ style="font-size:12;"
+ id="g587">
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="16.6979"
+ y="222.966"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect588" />
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="14.7335"
+ y="221.002"
+ transform="translate(-1.30962,-1.30992)"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect589" />
+ </g>
+ <rect
+ width="90.951"
+ height="44.4829"
+ x="25.6196"
+ y="206.028"
+ style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect594" />
+ <rect
+ width="90.951"
+ height="44.4829"
+ x="24.4229"
+ y="204.135"
+ style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect595" />
+ <text
+ x="85.575645"
+ y="282.300354"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+ id="text596">
+ <tspan
+ x="85.575600"
+ y="282.299988"
+ id="tspan607">
+JNDI</tspan>
+ </text>
+ <rect
+ width="90.951"
+ height="44.4829"
+ x="236.937"
+ y="206.791"
+ style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect610" />
+ <rect
+ width="90.951"
+ height="44.4829"
+ x="235.741"
+ y="204.898"
+ style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect611" />
+ <text
+ x="342.093201"
+ y="283.226410"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+ id="text612">
+ <tspan
+ x="342.092987"
+ y="283.226013"
+ id="tspan621">
+JTA</tspan>
+ </text>
+ <rect
+ width="90.951"
+ height="44.4829"
+ x="130.134"
+ y="206.791"
+ style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect616" />
+ <rect
+ width="90.951"
+ height="44.4829"
+ x="128.937"
+ y="204.898"
+ style="font-size:12;fill:#b3b3b3;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect617" />
+ <text
+ x="212.445343"
+ y="283.226410"
+ transform="scale(0.823795,0.823795)"
+ style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+ id="text618">
+ <tspan
+ x="212.445007"
+ y="283.226013"
+ id="tspan623">
+JDBC</tspan>
+ </text>
+ <g
+ transform="matrix(0.823795,0,0,0.823795,0.120302,6.19341)"
+ style="font-size:12;"
+ id="g637">
+ <g
+ transform="matrix(0.499515,0,0,0.415467,-0.237339,5.61339)"
+ id="g167">
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="61.8805"
+ y="68.4288"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect134" />
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="59.2613"
+ y="65.8095"
+ style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect135" />
+ </g>
+ <text
+ x="33.749969"
+ y="50.589706"
+ style="font-size:11;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text188">
+ <tspan
+ x="33.750000"
+ y="50.589699"
+ id="tspan635">
+Transient Objects</tspan>
+ </text>
+ </g>
+ <g
+ transform="matrix(0.823795,0,0,0.823795,0.120302,5.25349)"
+ style="font-size:12;"
+ id="g644">
+ <g
+ transform="matrix(0.297486,0,0,0.516482,230.251,36.9178)"
+ id="g364">
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="61.8805"
+ y="68.4288"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect365" />
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="59.2613"
+ y="65.8095"
+ style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect366" />
+ </g>
+ <text
+ x="277.123230"
+ y="85.155571"
+ style="font-size:11;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+ id="text367">
+ <tspan
+ x="277.122986"
+ y="85.155602"
+ id="tspan631">
+Persistent</tspan>
+ <tspan
+ x="277.122986"
+ y="96.155602"
+ id="tspan633">
+Objects</tspan>
+ </text>
+ </g>
+</svg>
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/images/hibernate_logo_a.png (from rev 14074, core/trunk/documentation/manual/fr-FR/src/main/docbook/images/hibernate_logo_a.png)
===================================================================
(Binary files differ)
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/images/lite.png (from rev 14074, core/trunk/documentation/manual/fr-FR/src/main/docbook/images/lite.png)
===================================================================
(Binary files differ)
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/images/lite.svg (from rev 14074, core/trunk/documentation/manual/fr-FR/src/main/docbook/images/lite.svg)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/images/lite.svg (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/images/lite.svg 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,334 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+ xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="318.898"
+ height="248.031"
+ id="svg1">
+ <defs
+ id="defs3">
+ <linearGradient
+ x1="0"
+ y1="0"
+ x2="1"
+ y2="0"
+ id="linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop128" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop129" />
+ </linearGradient>
+ <linearGradient
+ x1="0"
+ y1="0"
+ x2="1"
+ y2="0"
+ id="linearGradient130"
+ xlink:href="#linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad" />
+ <radialGradient
+ cx="0.5"
+ cy="0.5"
+ fx="0.5"
+ fy="0.5"
+ r="0.5"
+ id="radialGradient131"
+ xlink:href="#linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad" />
+ </defs>
+ <rect
+ width="291.837"
+ height="57.0074"
+ x="17.3169"
+ y="18.646"
+ style="font-size:12;fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect136" />
+ <rect
+ width="291.837"
+ height="57.0074"
+ x="13.9703"
+ y="16.2302"
+ style="font-size:12;fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect126" />
+ <g
+ transform="matrix(0.326107,0,0,0.765831,9.59261,8.98517)"
+ style="font-size:12;"
+ id="g161">
+ <rect
+ width="285.502"
+ height="118.523"
+ x="16.6979"
+ y="99.2053"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect137" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect132" />
+ </g>
+ <g
+ transform="matrix(1.02406,0,0,0.652953,0.223384,39.9254)"
+ style="font-size:12;"
+ id="g164">
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="16.6979"
+ y="222.966"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect138" />
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="14.7335"
+ y="221.002"
+ transform="translate(-1.30962,-1.30992)"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect133" />
+ </g>
+ <g
+ transform="matrix(0.449834,0,0,0.338463,-3.15909,9.73319)"
+ style="font-size:12;"
+ id="g167">
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="61.8805"
+ y="68.4288"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect134" />
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="59.2613"
+ y="65.8095"
+ style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect135" />
+ </g>
+ <text
+ x="302.277679"
+ y="65.943230"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text183">
+ <tspan
+ x="302.277954"
+ y="65.943184"
+ id="tspan360">
+Application</tspan>
+ </text>
+ <text
+ x="36.235924"
+ y="63.796055"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:14;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text188">
+ <tspan
+ x="36.235950"
+ y="63.796051"
+ id="tspan427">
+Transient Objects</tspan>
+ </text>
+ <text
+ x="180.416245"
+ y="290.543701"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:18;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text197">
+ <tspan
+ x="180.415939"
+ y="290.543549"
+ id="tspan421">
+Database</tspan>
+ </text>
+ <text
+ x="25.037701"
+ y="179.154755"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text216">
+ <tspan
+ x="25.037655"
+ y="179.154648"
+ id="tspan384">
+SessionFactory</tspan>
+ </text>
+ <g
+ transform="matrix(0.252763,0,0,0.765831,109.104,8.98517)"
+ style="font-size:12;"
+ id="g386">
+ <rect
+ width="285.502"
+ height="118.523"
+ x="16.6979"
+ y="99.2053"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect387" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect388" />
+ </g>
+ <g
+ transform="matrix(0.297394,0,0,0.572692,101.502,21.6359)"
+ style="font-size:12;"
+ id="g364">
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="61.8805"
+ y="68.4288"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect365" />
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="59.2613"
+ y="65.8095"
+ style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect366" />
+ </g>
+ <text
+ x="202.746506"
+ y="102.992203"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:14;font-weight:normal;stroke-width:1pt;font-family:Helvetica;text-anchor:middle;"
+ id="text367">
+ <tspan
+ x="202.746948"
+ y="102.992249"
+ id="tspan423">
+Persistent</tspan>
+ <tspan
+ x="202.746948"
+ y="116.992355"
+ id="tspan425">
+Objects</tspan>
+ </text>
+ <text
+ x="174.458496"
+ y="180.080795"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text389">
+ <tspan
+ x="174.458618"
+ y="180.080338"
+ id="tspan392">
+Session</tspan>
+ </text>
+ <g
+ transform="matrix(0.127369,0,0,0.765831,188.675,8.98517)"
+ style="font-size:12;"
+ id="g394">
+ <rect
+ width="285.502"
+ height="118.523"
+ x="16.6979"
+ y="99.2053"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect395" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect396" />
+ </g>
+ <text
+ x="260.413269"
+ y="179.154739"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text397">
+ <tspan
+ x="260.412964"
+ y="179.154343"
+ id="tspan400">
+JDBC</tspan>
+ </text>
+ <g
+ transform="matrix(0.127369,0,0,0.765831,229.156,8.98517)"
+ style="font-size:12;"
+ id="g405">
+ <rect
+ width="285.502"
+ height="118.523"
+ x="16.6979"
+ y="99.2053"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect406" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect407" />
+ </g>
+ <text
+ x="320.606903"
+ y="179.154739"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text408">
+ <tspan
+ x="320.606964"
+ y="179.154343"
+ id="tspan417">
+JNDI</tspan>
+ </text>
+ <g
+ transform="matrix(0.127369,0,0,0.765831,269.281,8.98517)"
+ style="font-size:12;"
+ id="g411">
+ <rect
+ width="285.502"
+ height="118.523"
+ x="16.6979"
+ y="99.2053"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect412" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect413" />
+ </g>
+ <text
+ x="377.096313"
+ y="179.154739"
+ transform="scale(0.73778,0.73778)"
+ style="font-size:16;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text414">
+ <tspan
+ x="377.096008"
+ y="179.154999"
+ id="tspan145">
+JTA</tspan>
+ </text>
+</svg>
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/images/overview.png (from rev 14074, core/trunk/documentation/manual/fr-FR/src/main/docbook/images/overview.png)
===================================================================
(Binary files differ)
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/images/overview.svg (from rev 14074, core/trunk/documentation/manual/fr-FR/src/main/docbook/images/overview.svg)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/images/overview.svg (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/images/overview.svg 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,250 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"
+[
+ <!ATTLIST svg
+ xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink">
+]>
+<!-- Created with Sodipodi ("http://www.sodipodi.com/") -->
+<svg
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ width="248.031"
+ height="248.031"
+ id="svg1">
+ <defs
+ id="defs3">
+ <linearGradient
+ x1="0"
+ y1="0"
+ x2="1"
+ y2="0"
+ id="linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0"
+ id="stop128" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1;"
+ offset="1"
+ id="stop129" />
+ </linearGradient>
+ <linearGradient
+ x1="0"
+ y1="0"
+ x2="1"
+ y2="0"
+ id="linearGradient130"
+ xlink:href="#linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad" />
+ <radialGradient
+ cx="0.5"
+ cy="0.5"
+ fx="0.5"
+ fy="0.5"
+ r="0.5"
+ id="radialGradient131"
+ xlink:href="#linearGradient127"
+ gradientUnits="objectBoundingBox"
+ spreadMethod="pad" />
+ </defs>
+ <g
+ transform="matrix(0.771934,0,0,0.771934,4.36019,-3.02123)"
+ style="font-size:12;"
+ id="g158">
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="16.6979"
+ y="17.3527"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect136" />
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="14.7335"
+ y="15.3883"
+ transform="translate(-1.30962,-1.30992)"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect126" />
+ </g>
+ <g
+ transform="matrix(0.771934,0,0,0.771934,4.36019,3.04452)"
+ style="font-size:12;"
+ id="g161">
+ <rect
+ width="285.502"
+ height="118.523"
+ x="16.6979"
+ y="99.2053"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect137" />
+ <rect
+ width="285.502"
+ height="118.523"
+ x="13.4238"
+ y="95.9309"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect132" />
+ </g>
+ <g
+ transform="matrix(0.771934,0,0,0.771934,4.36019,8.0993)"
+ style="font-size:12;"
+ id="g164">
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="16.6979"
+ y="222.966"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect138" />
+ <rect
+ width="285.502"
+ height="77.2688"
+ x="14.7335"
+ y="221.002"
+ transform="translate(-1.30962,-1.30992)"
+ style="fill:#d2d2d2;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect133" />
+ </g>
+ <g
+ transform="matrix(0.771934,0,0,0.543505,2.59104,21.1103)"
+ style="font-size:12;"
+ id="g167">
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="61.8805"
+ y="68.4288"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect134" />
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="59.2613"
+ y="65.8095"
+ style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect135" />
+ </g>
+ <text
+ x="105.392174"
+ y="56.568123"
+ transform="scale(0.771934,0.771934)"
+ style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text183">
+ <tspan
+ x="105.392273"
+ y="56.568146"
+ id="tspan186">
+Application</tspan>
+ </text>
+ <text
+ x="81.820183"
+ y="103.149330"
+ transform="scale(0.771934,0.771934)"
+ style="font-size:20;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text188">
+ <tspan
+ x="81.820213"
+ y="103.149727"
+ id="tspan206">
+Persistent Objects</tspan>
+ </text>
+ <text
+ x="111.548180"
+ y="278.927887"
+ transform="scale(0.771934,0.771934)"
+ style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text197">
+ <tspan
+ x="111.547874"
+ y="278.927551"
+ id="tspan200">
+Database</tspan>
+ </text>
+ <text
+ x="94.436180"
+ y="153.805740"
+ transform="scale(0.771934,0.771934)"
+ style="font-size:24;font-weight:normal;stroke-width:1pt;font-family:Helvetica;"
+ id="text216">
+ <tspan
+ x="94.436180"
+ y="153.805740"
+ id="tspan221">
+HIBERNATE</tspan>
+ </text>
+ <g
+ transform="matrix(0.771934,0,0,0.771934,2.59083,1.02261)"
+ style="font-size:12;"
+ id="g254">
+ <g
+ transform="translate(4.58374,2.61928)"
+ id="g176">
+ <g
+ transform="matrix(0.571429,0,0,0.67347,-10.6174,117.093)"
+ id="g170">
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="61.8805"
+ y="68.4288"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect171" />
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="59.2613"
+ y="65.8095"
+ style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect172" />
+ </g>
+ <g
+ transform="matrix(0.571429,0,0,0.67347,138.682,117.093)"
+ id="g173">
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="61.8805"
+ y="68.4288"
+ style="fill:#757575;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect174" />
+ <rect
+ width="199.065"
+ height="61.5532"
+ x="59.2613"
+ y="65.8095"
+ style="fill:#e0e0e0;fill-rule:evenodd;stroke-width:1pt;"
+ id="rect175" />
+ </g>
+ </g>
+ <text
+ x="47.259438"
+ y="182.367538"
+ style="font-weight:bold;stroke-width:1pt;font-family:Courier;"
+ id="text191">
+ <tspan
+ x="47.259399"
+ y="182.367996"
+ id="tspan212">
+hibernate.</tspan>
+ <tspan
+ x="47.259399"
+ y="194.367996"
+ id="tspan214">
+properties</tspan>
+ </text>
+ <text
+ x="198.523010"
+ y="188.260941"
+ style="font-weight:normal;stroke-width:1pt;font-family:helvetica;"
+ id="text194">
+ <tspan
+ id="tspan195">
+XML Mapping</tspan>
+ </text>
+ </g>
+</svg>
Copied: core/trunk/documentation/manual/es-ES/src/main/docbook/legal_notice.xml (from rev 14073, core/trunk/documentation/manual/en-US/src/main/docbook/legal_notice.xml)
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/legal_notice.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/legal_notice.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,52 @@
+<?xml version='1.0'?>
+<!DOCTYPE legalnotice PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
+<!--
+ ~ Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
+ ~
+ ~ This copyrighted material is made available to anyone wishing to use, modify,
+ ~ copy, or redistribute it subject to the terms and conditions of the GNU
+ ~ Lesser General Public License, v. 2.1. This program is distributed in the
+ ~ hope that it will be useful, but WITHOUT A WARRANTY; without even the implied
+ ~ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details. You should have received a
+ ~ copy of the GNU Lesser General Public License, v.2.1 along with this
+ ~ distribution; if not, write to the Free Software Foundation, Inc.,
+ ~ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ ~
+ ~ Red Hat Author(s): Steve Ebersole
+ -->
+<legalnotice id="Legal_Notice">
+ <title>Legal Notice</title>
+ <para>
+ <address>
+ <street>1801 Varsity Drive</street>
+ <city>Raleigh</city>, <state>NC</state><postcode>27606-2072</postcode><country>USA</country>
+ <phone>Phone: +1 919 754 3700</phone>
+ <phone>Phone: 888 733 4281</phone>
+ <fax>Fax: +1 919 754 3701</fax>
+ <pob>PO Box 13588</pob><city>Research Triangle Park</city>, <state>NC</state><postcode>27709</postcode><country>USA</country>
+ </address>
+ </para>
+ <para>
+ Copyright <trademark class="copyright"></trademark> 2007 by Red Hat, Inc. This material may be distributed only subject to the terms and conditions set forth in the Open Publication License, V1.0 or later (the latest version is presently available at <ulink url="http://www.opencontent.org/openpub/">http://www.opencontent.org/openpub/</ulink>).
+ </para>
+ <para>
+ Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder.
+ </para>
+ <para>
+ Distribution of the work or derivative of the work in any standard (paper) book form for commercial purposes is prohibited unless prior permission is obtained from the copyright holder.
+ </para>
+ <para>
+ Red Hat and the Red Hat "Shadow Man" logo are registered trademarks of Red Hat, Inc. in the United States and other countries.
+ </para>
+ <para>
+ All other trademarks referenced herein are the property of their respective owners.
+ </para>
+ <para>
+ The GPG fingerprint of the security at redhat.com key is:
+ </para>
+ <para>
+ CA 20 86 86 2B D6 9D FC 65 F6 EC C4 21 91 80 CD DB 42 A6 0E
+ </para>
+</legalnotice>
\ No newline at end of file
Added: core/trunk/documentation/manual/es-ES/src/main/docbook/legal_notice2.xml
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/legal_notice2.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/legal_notice2.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,16 @@
+<?xml version='1.0'?>
+<!DOCTYPE legalnotice PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
+<legalnotice id="Legal_Notice">
+ <title>Translation-specific Legal Notice</title>
+ <para>
+ Advertencia! Esta es una versión traducida del inglés de
+ la documentacién de referencia de Hibernate. La versión
+ traducida puede no estar actualizada! Sin embargo, las diferencias
+ deberían ser sólo menores. Consulta la documentación
+ de referencia en inglés si estás perdiendo información
+ o encuentras algún error de traducción. Si quieres colaborar con
+ una traducción en particular, contáctanos en la lista de correo
+ de desarrolladores de Hibernate.
+ </para>
+</legalnotice>
\ No newline at end of file
Deleted: core/trunk/documentation/manual/es-ES/src/main/docbook/master.xml
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/master.xml 2007-10-09 18:28:36 UTC (rev 14074)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/master.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -1,203 +0,0 @@
-<?xml version='1.0' encoding="iso-8859-1"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3CR3//EN"
- "../support/docbook-dtd/docbookx.dtd"
-[
-<!ENTITY quickstart SYSTEM "modules/quickstart.xml">
-<!ENTITY tutorial SYSTEM "modules/tutorial.xml">
-<!ENTITY architecture SYSTEM "modules/architecture.xml">
-<!ENTITY configuration SYSTEM "modules/configuration.xml">
-<!ENTITY persistent-classes SYSTEM "modules/persistent_classes.xml">
-<!ENTITY basic-mapping SYSTEM "modules/basic_mapping.xml">
-<!ENTITY collection-mapping SYSTEM "modules/collection_mapping.xml">
-<!ENTITY association-mapping SYSTEM "modules/association_mapping.xml">
-<!ENTITY component-mapping SYSTEM "modules/component_mapping.xml">
-<!ENTITY inheritance-mapping SYSTEM "modules/inheritance_mapping.xml">
-<!ENTITY session-api SYSTEM "modules/session_api.xml">
-<!ENTITY transactions SYSTEM "modules/transactions.xml">
-<!ENTITY events SYSTEM "modules/events.xml">
-<!ENTITY batch SYSTEM "modules/batch.xml">
-<!ENTITY query-hql SYSTEM "modules/query_hql.xml">
-<!ENTITY query-criteria SYSTEM "modules/query_criteria.xml">
-<!ENTITY query-sql SYSTEM "modules/query_sql.xml">
-<!ENTITY filters SYSTEM "modules/filters.xml">
-<!ENTITY xml SYSTEM "modules/xml.xml">
-<!ENTITY performance SYSTEM "modules/performance.xml">
-<!ENTITY toolset-guide SYSTEM "modules/toolset_guide.xml">
-<!ENTITY example-parentchild SYSTEM "modules/example_parentchild.xml">
-<!ENTITY example-weblog SYSTEM "modules/example_weblog.xml">
-<!ENTITY example-mappings SYSTEM "modules/example_mappings.xml">
-<!ENTITY best-practices SYSTEM "modules/best_practices.xml">
-]>
-
-<book lang="es">
-
- <bookinfo>
- <title>HIBERNATE - Persistencia Relacional para Java Idiomático</title>
- <subtitle>Documentación de Referencia de Hibernate</subtitle>
- <releaseinfo>3.0.5</releaseinfo>
- </bookinfo>
-
- <toc/>
-
- <preface id="preface" revision="2">
- <title>Prefacio</title>
-
- <para>
- Advertencia! Esta es una versión traducida del inglés de
- la documentacién de referencia de Hibernate. La versión
- traducida puede no estar actualizada! Sin embargo, las diferencias
- deberían ser sólo menores. Consulta la documentación
- de referencia en inglés si estás perdiendo información
- o encuentras algún error de traducción. Si quieres colaborar con
- una traducción en particular, contáctanos en la lista de correo
- de desarrolladores de Hibernate.
- </para>
-
- <para>
- Traductor(es): Bernardo Antonio Buffa Colomé <kreimer at bbs.frc.utn.edu.ar>
-<!--,
- Antonio López Gota <antoniogota at gmail.com> -->
- </para>
-
- <para>
- Trabajar con software orientado a objetos y una base de datos relacional puede ser
- incómodo y consumir tiempo en los entornos de empresa de hoy. Hibernate es una
- herramienta de mapeo objeto/relacional para entornos Java. El término mapeo
- objeto/relacional (MOR) hace referencia a la técnica de mapear una
- representación de datos desde un modelo de objetos a un modelo de datos relacional
- con un esquema basado en SQL.
- </para>
-
- <para>
- Hibernate no sólo se encarga de mapear de clases Java a tablas de base de datos
- (y de tipos de datos de Java a tipos de datos SQL), sino que también provee
- facilidades de consulta y recuperación de datos y puede reducir significativamente
- el tiempo de desarrollo que de otra forma se gasta en el manejo de los datos en SQL y JDBC.
- </para>
-
- <para>
- La meta de Hibernate es relevar al desarrollador del 95 por ciento de las tareas comunes
- relacionadas a la programación de la persistencia de los datos.
- Hibernate puede no ser la mejor solución para aplicaciones que usan solamente
- procedimientos almacenados para implementar la lógica de negocio en la base de
- datos, es mas útil con modelos de dominio orientados a objetos y lógica de
- negocio en middle-tier basada en Java. Sin embargo, Hibernate ciertamente puede ayudarte
- a quitar o encapsular código SQL específico de vendedor y ayudará
- con la tarea común de traducción de resultados desde una representación
- tabular a un grafo de objetos.
- </para>
-
- <para>
- Si eres nuevo en Hibernate y lo del Mapeo Objeto/Relacional o incluso en Java,
- sigue por favor estos pasos:
- </para>
-
- <orderedlist>
- <listitem>
- <para>
- Lee <xref linkend="quickstart"/> para un tutorial de 30 minutos, usando Tomcat.
- </para>
- </listitem>
- <listitem>
- <para>
- Lee <xref linkend="architecture"/> para entender los entornos en los que
- puede ser usado Hibernate.
- </para>
- </listitem>
- <listitem>
- <para>
- Dale una mirada al directorio <literal>eg/</literal> en la distribución
- de Hibernate, contiene una aplicación independiente simple.
- Copia tu driver JDBC al directorio <literal>lib/</literal> y edita
- <literal>etc/hibernate.properties</literal>, especificando los valores
- correctos para tu base de datos. Desde línea de comandos en el
- directorio de la distribución, tipea <literal>ant eg</literal>
- (usando Ant), o bajo Windows, tipea <literal>build eg</literal>.
- </para>
- </listitem>
- <listitem>
- <para>
- Usa esta documentación de referencia como tu fuente de información
- primaria. Ten en consideración leer <emphasis>Java Persistence with Hibernate</emphasis>
- (http://www.manning.com/bauer2) si necesitas mas ayuda con el diseño
- de aplicaciones o si prefieres un tutorial paso a paso.
- Visita también http://caveatemptor.hibernate.org y descarga la aplicación
- de ejemplo para Java Persistence with Hibernate.
- </para>
- </listitem>
- <listitem>
- <para>
- Los FAQs son respondidos en el sitio web de Hibernate.
- </para>
- </listitem>
- <listitem>
- <para>
- En el sitio web de Hibernate hay enlaces a demos de terceros, ejemplos
- y tutoriales.
- </para>
- </listitem>
- <listitem>
- <para>
- El Area de Comunidad en el sitio web de Hibernate es una buena fuente
- de patrones de diseño y varias soluciones de integración
- (Tomcat, JBoss, Struts, EJB, etc.).
- </para>
- </listitem>
- </orderedlist>
-
- <para>
- Si tienes preguntas, usa el foro de usuarios enlazado en el sitio web de Hibernate.
- También proveemos un sistema de seguimiento JIRA para reportes de defectos y
- peticiones de nuevas características.
- Si estas interesado en el desarrollo de Hibernate, únete a la lista de correo
- de desarrolladores. Si estas interesado en traducir esta documentación a tu
- lenguaje, contáctanos en la lista de correo de desarrolladores.
- </para>
-
- <para>
- A través de JBoss Inc. (see http://www.hibernate.org/SupportTraining/) hay
- disponibilidad de soporte comercial de desarrollo, soporte de producción y
- entrenamiento en Hibernate.
- Hibernate es un proyecto de la suite de productos de código abierto
- JBoss Professional.
- </para>
-
- </preface>
-
- &quickstart;
- &tutorial;
- &architecture;
-
- &configuration;
-
- &persistent-classes;
-
- &basic-mapping;
- &collection-mapping;
- &association-mapping;
- &component-mapping;
- &inheritance-mapping;
-
- &session-api;
- &transactions;
- &events;
- &batch;
-
- &query-hql;
- &query-criteria;
- &query-sql;
- &filters;
- &xml;
-
- &performance;
-
- &toolset-guide;
-
- &example-parentchild;
- &example-weblog;
- &example-mappings;
-
- &best-practices;
-
-</book>
-
Added: core/trunk/documentation/manual/es-ES/src/main/docbook/translators.xml
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/translators.xml (rev 0)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/translators.xml 2007-10-09 18:45:36 UTC (rev 14075)
@@ -0,0 +1,10 @@
+<?xml version='1.0'?>
+
+<!DOCTYPE authorgroup PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
+<authorgroup id="AuthorGroup">
+ <othercredit class="translator">
+ <othername><![CDATA[Bernardo Antonio Buffa Colomé]]></othername>
+ <email>kreimer at bbs.frc.utn.edu.ar</email>
+ </othercredit>
+</authorgroup>
\ No newline at end of file
More information about the hibernate-commits
mailing list