From 1a839084d0ba42c466ec1902cf11daa098417783 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Tue, 9 Oct 2007 18:45:36 +0000 Subject: [PATCH] new docbook layout (prep for translations migration to PO) git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@14075 1b8cb986-b30d-0410-93ca-fae66ebed9b2 --- .../src/main/docbook/Hibernate_Reference.xml | 88 + .../src/main/docbook/content/architecture.xml | 279 ++ .../docbook/content/association_mapping.xml | 527 +++ .../main/docbook/content/basic_mapping.xml | 3222 +++++++++++++++++ .../es-ES/src/main/docbook/content/batch.xml | 192 + .../main/docbook/content/best_practices.xml | 229 ++ .../docbook/content/collection_mapping.xml | 1241 +++++++ .../docbook/content/component_mapping.xml | 403 +++ .../main/docbook/content/configuration.xml | 1761 +++++++++ .../es-ES/src/main/docbook/content/events.xml | 233 ++ .../main/docbook/content/example_mappings.xml | 654 ++++ .../docbook/content/example_parentchild.xml | 362 ++ .../main/docbook/content/example_weblog.xml | 429 +++ .../src/main/docbook/content/filters.xml | 130 + .../docbook/content/inheritance_mapping.xml | 464 +++ .../src/main/docbook/content/performance.xml | 1334 +++++++ .../docbook/content/persistent_classes.xml | 478 +++ .../{master.xml => content/preface.xml} | 101 +- .../main/docbook/content/query_criteria.xml | 431 +++ .../src/main/docbook/content/query_hql.xml | 1107 ++++++ .../src/main/docbook/content/query_sql.xml | 477 +++ .../src/main/docbook/content/quickstart.xml | 666 ++++ .../src/main/docbook/content/session_api.xml | 1224 +++++++ .../main/docbook/content/toolset_guide.xml | 459 +++ .../src/main/docbook/content/transactions.xml | 925 +++++ .../src/main/docbook/content/tutorial.xml | 1270 +++++++ .../es-ES/src/main/docbook/content/xml.xml | 282 ++ .../src/main/docbook/images/AuthorWork.png | Bin 0 -> 6000 bytes .../images/AuthorWork.zargo | Bin .../docbook/images/CustomerOrderProduct.png | Bin 0 -> 5035 bytes .../images/CustomerOrderProduct.zargo | Bin .../main/docbook/images/EmployerEmployee.png | Bin 0 -> 8512 bytes .../images/EmployerEmployee.zargo | Bin .../src/main/docbook/images/full_cream.png | Bin 0 -> 9359 bytes .../shared => docbook}/images/full_cream.svg | 0 .../images/hibernate_logo_a.png | Bin .../es-ES/src/main/docbook/images/lite.png | Bin 0 -> 6821 bytes .../shared => docbook}/images/lite.svg | 0 .../src/main/docbook/images/overview.png | Bin 0 -> 8433 bytes .../shared => docbook}/images/overview.svg | 0 .../es-ES/src/main/docbook/legal_notice.xml | 52 + .../es-ES/src/main/docbook/legal_notice2.xml | 16 + .../es-ES/src/main/docbook/translators.xml | 10 + .../src/main/resources/shared/css/html.css | 97 - .../resources/shared/images/AuthorWork.gif | Bin 7186 -> 0 bytes .../shared/images/CustomerOrderProduct.gif | Bin 6187 -> 0 bytes .../shared/images/EmployerEmployee.gif | Bin 9779 -> 0 bytes .../resources/shared/images/full_cream.gif | Bin 9286 -> 0 bytes .../src/main/resources/shared/images/lite.gif | Bin 6764 -> 0 bytes .../main/resources/shared/images/overview.gif | Bin 8578 -> 0 bytes 50 files changed, 18950 insertions(+), 193 deletions(-) create mode 100644 documentation/manual/es-ES/src/main/docbook/Hibernate_Reference.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/content/architecture.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/content/association_mapping.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/content/basic_mapping.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/content/batch.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/content/best_practices.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/content/collection_mapping.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/content/component_mapping.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/content/configuration.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/content/events.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/content/example_mappings.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/content/example_parentchild.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/content/example_weblog.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/content/filters.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/content/inheritance_mapping.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/content/performance.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/content/persistent_classes.xml rename documentation/manual/es-ES/src/main/docbook/{master.xml => content/preface.xml} (60%) create mode 100644 documentation/manual/es-ES/src/main/docbook/content/query_criteria.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/content/query_hql.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/content/query_sql.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/content/quickstart.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/content/session_api.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/content/toolset_guide.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/content/transactions.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/content/tutorial.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/content/xml.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/images/AuthorWork.png rename documentation/manual/es-ES/src/main/{resources/shared => docbook}/images/AuthorWork.zargo (100%) create mode 100644 documentation/manual/es-ES/src/main/docbook/images/CustomerOrderProduct.png rename documentation/manual/es-ES/src/main/{resources/shared => docbook}/images/CustomerOrderProduct.zargo (100%) create mode 100644 documentation/manual/es-ES/src/main/docbook/images/EmployerEmployee.png rename documentation/manual/es-ES/src/main/{resources/shared => docbook}/images/EmployerEmployee.zargo (100%) create mode 100644 documentation/manual/es-ES/src/main/docbook/images/full_cream.png rename documentation/manual/es-ES/src/main/{resources/shared => docbook}/images/full_cream.svg (100%) rename documentation/manual/es-ES/src/main/{resources/shared => docbook}/images/hibernate_logo_a.png (100%) create mode 100644 documentation/manual/es-ES/src/main/docbook/images/lite.png rename documentation/manual/es-ES/src/main/{resources/shared => docbook}/images/lite.svg (100%) create mode 100644 documentation/manual/es-ES/src/main/docbook/images/overview.png rename documentation/manual/es-ES/src/main/{resources/shared => docbook}/images/overview.svg (100%) create mode 100644 documentation/manual/es-ES/src/main/docbook/legal_notice.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/legal_notice2.xml create mode 100644 documentation/manual/es-ES/src/main/docbook/translators.xml delete mode 100644 documentation/manual/es-ES/src/main/resources/shared/css/html.css delete mode 100644 documentation/manual/es-ES/src/main/resources/shared/images/AuthorWork.gif delete mode 100644 documentation/manual/es-ES/src/main/resources/shared/images/CustomerOrderProduct.gif delete mode 100644 documentation/manual/es-ES/src/main/resources/shared/images/EmployerEmployee.gif delete mode 100644 documentation/manual/es-ES/src/main/resources/shared/images/full_cream.gif delete mode 100644 documentation/manual/es-ES/src/main/resources/shared/images/lite.gif delete mode 100644 documentation/manual/es-ES/src/main/resources/shared/images/overview.gif diff --git a/documentation/manual/es-ES/src/main/docbook/Hibernate_Reference.xml b/documentation/manual/es-ES/src/main/docbook/Hibernate_Reference.xml new file mode 100644 index 0000000000..5a0daf7354 --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/Hibernate_Reference.xml @@ -0,0 +1,88 @@ + + + + + +]> + + + + + HIBERNATE - Persistencia Relacional para Java Idiomático + Documentación de Referencia de Hibernate + &versionNumber; + &versionNumber; + 1 + + + + + + + + + + ©rightYear; + ©rightHolder; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documentation/manual/es-ES/src/main/docbook/content/architecture.xml b/documentation/manual/es-ES/src/main/docbook/content/architecture.xml new file mode 100644 index 0000000000..9d98dd12ff --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/content/architecture.xml @@ -0,0 +1,279 @@ + + + Arquitectura + + + Visión General + + + Una visión a (muy) alto nivel de la arquitectura de Hibernate: + + + + + + + + + + + + + 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. + + + + 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: + + + + + + + + + + + + + La arquitectura "full cream" abstrae a la aplicación de las APIs + de JDBC/JTA y deja que Hibernate se encargue de los detalles. + + + + + + + + + + + + + He aquí algunas definiciones de los objetos en los diagramas: + + + SessionFactory (org.hibernate.SessionFactory) + + + Caché threadsafe (inmutable) de mapeos compilados para + una sola base de datos. Es una fábrica de Session + y un cliente de ConnectionProvider. Opcionalmente, + puede mantener una caché (de segundo nivel) de datos reusables + entre transacciones, a un nivel de proceso o de cluster. + + + + + Session (org.hibernate.Session) + + + 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 Transaction. + Mantiene una caché requerida (de primer nivel) de objetos persistentes, + usada mientras se navega el grafo de objetos o se recuperen objetos por + identificador. + + + + + Objetos y colecciones persistentes + + + 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) Session. Tan pronto como la + Session 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). + + + + + Objetos y colecciones transitorios y separados + + + Instancias de clases persistentes que no estan acutualmente asociadas + con una Session. Pueden haber sido instanciadas por + la aplicación y (aún) no haber sido hechas persistentes, + o pueden haber sido instanciadas por una Session cerrada. + + + + + Transaction (org.hibernate.Transaction) + + + (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 + Session puede extenderse sobre varias Transactions. + Sin embargo, la demarcación de la transacción, ya sea usando la API + subyacente o Transaction, nunca es opcional! + + + + + ConnectionProvider (org.hibernate.connection.ConnectionProvider) + + + (Opcional) Una fábrica (y pool) de conexiones JDBC. Abstrae a la aplicación + del Datasource o DriverManager subyacente. + No se expone a la aplicación, pero puede ser extendido/implementado por + el desarrollador. + + + + + TransactionFactory (org.hibernate.TransactionFactory) + + + (Opcional) Una fábrica de instancias de Transaction. + No se expone a la aplicación, pero puede ser extendido/implementado por + el desarrollador. + + + + + Interfaces de Extensión + + + 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. + + + + + + + + Dada una arquitectura "sencilla", la aplicación pasa por alto las APIs + de Transaction/TransactionFactory y/o + ConnectionProvider, para hablar directamente a JTA o JDBC. + + + + + Estados de instancia + + Una instancia de una clase persistente puede estar en uno de tres estados + diferentes, definidos respecto de su contexto de persistencia. + El objeto Session de Hibernate es el contexto de persistencia: + + + + + transitorio + + + La instancia no está y nunca estuvo asociada con + un contexto de persistencia. No tiene identidad persistente + (valor de clave primaria). + + + + + persistente + + + 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 garantiza + que la identidad persistente es equivalente a la identidad + Java (localización en memoria del objeto). + + + + + separado + + + 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. + + + + + + + + Integración JMX + + + 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, + org.hibernate.jmx.HibernateService. + + + + 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: + + + + + + Gestión de Sesión: El ciclo de vida de la Session + 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 Session 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 + Transaction de Hibernate para esto). Para acceder a una + Session llama al HibernateContext. + + + + + Despliegue de HAR: 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 SessionFactory 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 más información sobre estas opciones, consulta la + Guía de Usuario del JBoss AS. + + + + Otra funcionalidad disponible como un servicio JMX son las estadísticas en + tiempo de ejecución de Hibernate. Mira . + + + + + Soporte JCA: + + 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. + + + + + diff --git a/documentation/manual/es-ES/src/main/docbook/content/association_mapping.xml b/documentation/manual/es-ES/src/main/docbook/content/association_mapping.xml new file mode 100644 index 0000000000..80a543664e --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/content/association_mapping.xml @@ -0,0 +1,527 @@ + + + Mapeos de Asociación + + + Introducción + + + 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 Person y Address + en todos los ejemplos. + + + + Clasificaremos las asociaciones por cuanto mapeen o no a una tabla + de unión interviniente, y por su multiplicidad. + + + + 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. + + + + + + Asociaciones Unidireccionales + + + muchos a uno + + + Una asociación unidireccional muchos-a-uno es el tipo + más común de asociaciones unidireccionales. + + + + + + + + + + + + + +]]> + + + + + + uno a uno + + + Una asociación unidireccional uno-a-uno en una clave primaria + es casi idéntica. La única diferencia es la restricción de unicidad + de la columna. + + + + + + + + + + + + + +]]> + + + + Usualmente, una asociación unidireccional uno-a-uno en una + clave primaria usa un generador de id especial. (Observa que hemos + invertido el sentido de la asociación en este ejemplo). + + + + + + + + + + + + person + + + +]]> + + + + + + uno a muchos + + + Una asociación unidireccional uno-a-muchos en una clave foránea + es un caso muy inusual, y realmente no está recomendada. + + + + + + + + + + + + + + + + +]]> + + + + Creemos que es mejor usar una tabla de unión para este tipo de asociación. + + + + + + + + Asociaciones unidireccionales con tablas de unión + + + uno a muchos + + + Una asociación unidireccional uno-a-muchos en una tabla de unión + es más preferible. Observa que especificando unique="true", hemos + cambiado la multiplicidad de muchos-a-muchos a uno-a-muchos. + + + + + + + + + + + + + + + + +]]> + + + + + + muchos a uno + + + Una asociación unidireccional muchos-a-uno en una tabla de unión + es bastante común cuando la asociación es opcional. + + + + + + + + + + + + + + + + +]]> + + + + + + uno a uno + + + Una asociación unidireccional uno-a-uno en una tabla de unión + es inusual en extremo, pero posible. + + + + + + + + + + + + + + + + +]]> + + + + + + muchos a muchos + + + Finalmente, tenemos una asociación unidireccional muchos-a-muchos + + + + + + + + + + + + + + + + +]]> + + + + + + + + Asociaciones Bidireccionales + + + uno a muchos / muchos a uno + + + Una asociación bidireccional muchos-a-uno es + el tipo más común de asociación. (Esta es la relación + estándar padre/hijo.) + + + + + + + + + + + + + + + + + +]]> + + + + + + + uno a uno + + + Una asociación bidireccional uno-a-uno en una clave foránea + es bastante común. + + + + + + + + + + + + + + +]]> + + + + Una asociación bidireccional uno-a-uno en una clave primaria + usa el generador de id especial. + + + + + + + + + + + + + person + + + +]]> + + + + + + + + Asociaciones bidireccionales con tablas de unión + + + uno a muchos / muchos a uno + + + Una asociación bidireccional uno-a-muchos en una tabla de unión. + Observa que el inverse="true" puede ir a cualquier lado de la asociación, + en la colección, o en la unión. + + + + + + + + + + + + + + + + + + + + +]]> + + + + + + uno a uno + + + Una asociación bidireccional uno-a-uno en una tabla de unión + es inusual en extremo, pero posible. + + + + + + + + + + + + + + + + + + + + +]]> + + + + + + muchos a muchos + + + Finalmente, tenemos una asociación bidireccional muchos-a-muchos. + + + + + + + + + + + + + + + + + + + + +]]> + + + + + + + + + + diff --git a/documentation/manual/es-ES/src/main/docbook/content/basic_mapping.xml b/documentation/manual/es-ES/src/main/docbook/content/basic_mapping.xml new file mode 100644 index 0000000000..13680bd9ba --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/content/basic_mapping.xml @@ -0,0 +1,3222 @@ + + Mapeo O/R Básico + + + Declaración de mapeo + + + 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. + + + + 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. + + + + Comencemos por un mapeo de ejemplo: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]]> + + + 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 not-null.) + + + + + + Doctype + + + Todos los mapeos XML deben declarar el doctype mostrado. El DTD actual puede + ser encontrado en el URL mencionado arriba, en el directorio + hibernate-x.x.x/src/org/hibernate, o en hibernate3.jar. + 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. + + + + + hibernate-mapping + + + Este elemento tiene muchos atributos opcionales. Los atributos schema + y catalog 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 + default-cascade especifica qué estilo de cascada debe asumirse + para las propiedades y colecciones que no especifican un atributo cascade. + El atributo auto-import nos permite usar nombres de clase sin cualificar + en el lenguaje de consulta, por defecto. + + + + + + + + + + + + + ]]> + + + + schema (opcional): El nombre de un esquema de la base de datos. + + + + + catalog (opcional): El nombre de un catálogo de la base de datos. + + + + + default-cascade (opcional - por defecto a none): + Un estilo de cascada por defecto. + + + + + default-access (opcional - por defecto a property): + La estrategia que Hibernate debe usar para acceder a todas las propiedades. + Puede ser una implementación personalizada de PropertyAccessor. + + + + + default-lazy (opcional - por defecto a true): + El valor por defecto para los atributos lazy de mapeos de clase + y colleción no especificados. + + + + + auto-import (opcional - por defecto a true): + Especifica si podemos usar nombres de clases no cualificados (de clases en este mapeo) + en el lenguaje de consulta. + + + + + package (opcional): Especifica un prefijo de paquete a asumir + para los nombres no cualificados de clase en el documento de mapeo. + + + + + + + Si tienes dos clases persistentes con el mismo nombre (sin cualificar), debes establecer + auto-import="false". Hibernate lanzará una excepción si + intentas asignar dos clases al mismo nombre "importado". + + + + Observa que el elemento hibernate-mapping te permite anidar + muchos mapeos <class> 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, Cat.hbm.xml, Dog.hbm.xml, + o, si se usa herencia, Animal.hbm.xml. + + + + + + class + + + Puedes declarar una clase persistente usando el elemento class: + + + + + + + + + + + + + + + + + + + + + + + + + + + ]]> + + + + name (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. + + + + + table (opcional - por defecto al nombre no cualificado de la clase): + El nombre de su tabla en base de datos. + + + + + discriminator-value (opcional - por defecto al nombre de la clase): + Un valor que distingue subclases individuales, usado para el comportamiento + polimórfico. Los valores aceptables incluyen null + y not null. + + + + + mutable (opcional, por defecto a true): + Especifica que las instancias de la clase (no) son mutables. + + + + + schema (opcional): Sobreescribe el nombre de esquema especificado + por el elemento raíz <hibernate-mapping>. + + + + + catalog (opcional): Sobreescribe el nombre de catálogo + especificado por el elemento raíz <hibernate-mapping>. + + + + + proxy (opcional): Especifica una interface a usar para proxies + de inicialización perezosa. Puedes especificar el nombre mismo de la clase. + + + + + dynamic-update (opcional, por defecto a false): + Especifica que el SQL UPDATE debe ser generado en tiempo de + ejecución y contener solamente aquellas columnas cuyo valor haya cambiado. + + + + + dynamic-insert (opcional, por defecto a false): + Especifica que el SQL INSERT debe ser generado en tiempo de + ejecución y contener solamente aquellas columnas cuyo valores no son nulos. + + + + + select-before-update (opcional, por defecto a false): + Especifica que Hibernate nunca debe realizar un SQL UPDATE + 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 update()), esto significa que Hibernate + realizará una SQL SELECT extra para determinar si un + UPDATE es realmente requerido. + + + + + polymorphism (opcional, por defecto a implicit): + Determina si se usa polimorfismo de consulta implícito o explícito. + + + + + where (opcional) especifica una condición SQL WHERE + arbitraria paraa ser usada al recuperar objetos de esta clase. + + + + + persister (opcional): Especifica un ClassPersister + personalizado. + + + + + batch-size (opcional, por defecto a 1) + especifica un "tamaño de lote" para traer instancias de esta clase por + identificador. + + + + + optimistic-lock (opcional, por defecto a version): + Determina la estrategia optimista de bloqueo. + + + + + lazy (opcional): + La recuperación perezosa puede ser deshabilitada por completo estableciendo + lazy="false". + + + + + entity-name (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 + y . + + + + + check (opcional): Una expresión SQL usada para generar + una restricción check multi-fila para la generación + automática de esquema. + + + + + rowid (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 rowid para actualizaciones rápidas si estableces esta + opción a rowid. Un ROWID es un detalle de implementación + y representa la posición física de la tupla almacenada. + + + + + subselect (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. + + + + + abstract (opcional): Usado para marcar superclases abstractas en + jerarquías <union-subclass>. + + + + + + + Es perfectamente aceptable que la clase persistente mencionada sea una interface. + Entonces declararías clases que implementan esa interface usando el elemento + <subclass>. Puedes persistir cualquier clase interna + estática. Debes especificar el nombre de la clase usando la forma + estándar. Por ejemplo, eg.Foo$Bar. + + + + Las clases inmutables, mutable="false", no pueden ser actualizadas o + borradas por la aplicación. Esto permite a Hibernate hacer ciertas optimizaciones + menores de rendimiento. + + + + El atributo opcional proxy 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. + + + + Por polimorfismo implícito 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 explícito 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 <class> como una + <subclass> o <joined-subclass>. + Para la mayoría de los propósitos el defecto, + polymorphism="implicit", 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). + + + + El atributo persister te permite personalizar la estrategia de persistencia + para la clase. Puedes, por ejemplo, especificar tu propia subclase de + org.hibernate.persister.EntityPersister o incluso puedes proveer una implementación + completamente nueva de la interface org.hibernate.persister.ClassPersister 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 Hashtable) mira + org.hibernate.test.CustomPersister. + + + + Observa que los valores de dynamic-update y dynamic-insert + no son heredados por las subclases y por lo tanto deben especificarse en los elementos + <subclass> o <joined-subclass>. + Estos ajustes pueden incrementar el rendimiento en algunos casos, pero podrían mermarlo en otros. + Ten juicio en su uso. + + + + Generalmente el uso de select-before-update 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 Session. + + + + Si habilitas dynamic-update, tendrás opción de estrategias + de bloqueo optimistas: + + + + + version chequea las columnas de versión/timestamp + + + + + all chequea todas las columnas + + + + + dirty chequea las columnas modificadas, permitiendo algunas + actualizaciones concurrentes + + + + + none no usa bloqueo optimista + + + + + Recomendamos muy 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 Session.merge()). + + + + 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. + + + + + select item.name, max(bid.amount), count(*) + from item + join bid on bid.item_id = item.id + group by item.name + + + + + ... +]]> + + + 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 <subselect> está disponible tanto + como un atributo o como un elemento anidado de mapeo. + + + + + + id + + + Las clases mapeadas deben 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 + <id> define el mapeo de esa propiedad a la columna de clave primaria. + + + + + + + + + + + + + +]]> + + + + name (opcional): El nombre de la propiedad del indentificador. + + + + + type (opcional): Un nombre que indica el tipo Hibernate. + + + + + column (opcional - por defecto al nombre de la propiedad): + El nombre de la columna de clave primaria. + + + + + unsaved-value (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. + + + + + access (opcional - por defecto a property): + La estrategia que Hibernate debe usar para acceder al valor de la propiedad. + + + + + + + Si se omite el atributo name, se asume que la clase no tiene propiedad + identificadora. + + + + El atributo unsaved-value 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. + + + + Hay una declaración <composite-id> alternativa para permitir acceso + a datos heredados con claves compuestas. Desalentamos fuertemente su uso para cualquier otra cosa. + + + + Generator + + + El elemento hijo opcional <generator> 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 <param>. + + + + + uid_table + next_hi_value_column + +]]> + + + Todos los generadores implementan la interface org.hibernate.id.IdentifierGenerator. + 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: + + + increment + + + genera indentificadores de tipo long, short o + int que sólo son únicos cuando ningún otro proceso + está insertando datos en la misma tabla. No usar en un cluster. + + + + + identity + + + soporta columnas de identidad en DB2, MySQL, MS SQL Server, Sybase y + HypersonicSQL. El identificador devuelto es de tipo long, + short o int. + + + + + sequence + + + usa una secuencia en DB2, PostgreSQL, Oracle, SAP DB, McKoi o un generador + en Interbase. El identificador devuelto es de tipo long, + short o int. + + + + + hilo + + + usa un algoritmo alto/bajo para generar eficientemente identificadores de tipo + long, short o int, + dada una tabla y columna como fuente de valores altos (por defecto + hibernate_unique_key y next_hi respectivamente). + El algoritmo alto/bajo genera identificadores que son únicos sólo para una + base de datos particular. + + + + + seqhilo + + + usa un algoritmo alto/bajo para generar eficientemente identificadores de tipo + long, short o int, + dada una secuencia de base de datos. + + + + + uuid + + + 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. + + + + + guid + + + usa una cadena GUID generada por base de datos en MS SQL Server y MySQL. + + + + + native + + + selecciona identity, sequence o + hilo dependiendo de las capacidades de la base de datos + subyacente. + + + + + assigned + + + deja a la aplicación asignar un identificador al objeto antes + de que se llame a save(). Esta es la estrategia + por defecto si no se especifica un elemento <generator>. + + + + + select + + + 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. + + + + + foreign + + + usa el identificador de otro objeto asociado. Generalmente usado en conjuncón + a una asociacón de clave primaria <uno-a-uno> + + + + + + + + + + Algoritmo alto/bajo + + Los generadores hilo y seqhilo 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). + + + + + hi_value + next_value + 100 + +]]> + + + + hi_value + 100 + +]]> + + + Desafortunadamente, no puedes usar hilo cuando le proveas tu propia + Connection a Hibernate. Cuando Hibernate está usando un datasource + del servidor de aplicaciones para obtener conexiones alistadas con JTA, debes configurar + correctamente el hibernate.transaction.manager_lookup_class. + + + + + Algoritmo UUID + + 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. + + + + + Columnas de identidad y secuencias + + Para las bases de datos que soportan columnas de identidad (DB2, MySQL, Sybase, MS SQL), + puedes usar generación de claves identity. Para las bases de datos + que soportan secuencias (DB2, Oracle, PostgreSQL, Interbase, McKoi, SAP DB) puedes usar la generación + de claves del estilo sequence. Ambas estrategias requieren dos consultas SQL + para insertar un nuevo objeto. + + + + + person_id_sequence + +]]> + + + +]]> + + + Para desarrollos multiplataforma, la estrategia native + eiligirá de entre las estrategias identity, + sequence y hilo, dependiendo de las capacidades + de la base de datos subyacentes. + + + + + Identificadores asignados + + Si quieres que la aplicación asigne los identificadores (en contraposición + a que los genere Hibernate), puedes usar el generador assigned. + 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 <generator>. + + + + Elegir el generador assigned hace que Hibernate use + unsaved-value="undefined", 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 + Interceptor.isUnsaved(). + + + + + Claves primarias asignadas por disparadores + + Para esquemas heredados solamente (Hibernate no genera DDL con disparadores). + + + + + socialSecurityNumber + +]]> + + + En el ejemplo de arriba, hay una propiedad ánica llamada + socialSecurityNumber definida por la clase, como + una clave natural, y una clave sustituta llamada person_id + cuyo valor es generado por un disparador. + + + + + + + + composite-id + + + + + + ...... +]]> + + + Para una tabla con clave compuesta, puedes mapear múltiples propiedades + de la clase como propiedades identificadoras. El elemento <composite-id> + acepta los mapeos de propiedad <key-property> y + los mapeos <key-many-to-one> como elementos hijo. + + + + + +]]> + + + Tu clase persistente debe sobreescribir equals() + y hashCode() para implementar igualdad de identificador compuesto. + Debe también implementar Serializable. + + + + 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 load() 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 . + Los atributos descriptos debajo solamente se aplican a este enfoque alternativo: + + + + + + name (opcional): Una propiedad de tipo componente que tiene el identificador + compuesto (ver siguiente sección). + + + + + class (opcional - por defecto al tipo de la propiedad determinado + por reflección): La clase del componente usado como identificador compuesto (ver siguiente sección). + + + + + unsaved-value (opcional - por defecto a undefined): + Indica que las instancias transitorias deben ser consideradas como recién instanciadas, + si se establece a any, o separadas, si se establece a none. + Lo mejor + + Indicates that transient instances should be considered newly instantiated, if set + to any, or detached, if set to none. + Lo mejor en todos los casos es dejar el valor por defecto. + + + + + + + + discriminator + + + El elemento <discriminator> 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: + string, character, integer, + byte, short, boolean, + yes_no, true_false. + + + + + + + + + + + ]]> + + + + column (opcional - por defecto a class) el + nombre de la columna discriminadora. + + + + + type (opcional - por defecto a string) un + nombre que indique el tipo Hibernate + + + + + force (optconal - por defecto a false) + "fuerza" a Hibernate a especificar valores discriminadores permitidos incluso + cuando se recuperan todas las instancias de la clase raíz. + + + + + insert (opcional - por defecto a true) + establezca este a false 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 INSERTs.) + + + + + formula (opcional) una expresión SQL arbitraria que + es ejecutada cuando un tipo tenga que ser evaluado. Permite dicriminación + basada en el contenido. + + + + + + + Los valores reales de la columna discriminadora están especificados por + el atributo discriminator-value de los elementos + <class> y <subclass>. + + + + El atributo force 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. + + + + Usando el atributo formula puedes declarar una expresión SQL + arbitraria que será usada para evaluar el tipo de una fila: + + + ]]> + + + + + version (opcional) + + + El elemento <version> es opcional e indica que la + tabla contiene datos versionados. Esto es particularmente útil si planeas + usar transacciones largas (ver debajo). + + + + + + + + + + + ]]> + + + + column (opcional - por defecto al nombre de la propiedad): El nombre + de la columna que tiene el número de versión. + + + + + name: El nombre de una propiedad de la clase persistente. + + + + + type (opcional - por defecto a integer): + El tipo del nú.mero de vesión. + + + + + access (opcional - por defecto a property): La + estrategia que Hibernate debe usar para acceder al valor de la propiedad. + + + + + unsaved-value (opcional - por defecto a undefined): + 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. + (undefined especifica que debe usarse el valor de la + propiedad identificadora.) + + + + + + + Los números de versión deben ser de tipo long, + integer, short, timestamp o + calendar de Hibernate. + + + + 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 + unsaved-value se hayan especificado. + 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! + + + + + timestamp (opcional) + + + El elemento opcional <timestamp> 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. + + + + + + + + + + ]]> + + + + column (opcional - por defecto al nombre de la propiedad): El nombre + de una columna que tiene el timestamp. + + + + + name: El nombre de una propiedad del estilo JavaBeans de tipo + Java Date o Timestamp de la clase persistente. + + + + + access (opcional - por defecto a property): La + estrategia que Hibernate debe usar para acceder al valor de la propiedad. + + + + + unsaved-value (opcional - por defecto a null): + 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. + (undefined especifica que debe usarse el valor de la propiedad + identificadora.) + + + + + + + Note that <timestamp> is equivalent to + <version type="timestamp">. + + + + + + property + + + El elemento <property> declara una propiedad persistente estilo + JavaBean de la clase. + + + + + + + + + + + + + + + + + + + ]]> + + + + name: el nombre de la propiedad, con la letra inicial + en minúsculas. + + + + + column (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) <column> anidado(s). + + + + + type (opcional): un nombre que indica el nobre Hibernate. + + + + + update, insert (opcional - por defecto a true) : + especifica que las columnas mapeadas deben ser incluídas en las sentencias SQL + UPDATE y/o INSERT . Especificando ambas a + false 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. + + + + + formula (opcional): una expresión SQL que define el valor + para una propiedad computada. Las propiedades computadas no tienen + una columna mapeada propia. + + + + + access (opcional - por defecto a property): La + estrategia que Hibernate debe usar para acceder al valor de la propiedad. + + + + + lazy (opcional - por defecto a false): 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). + + + + + unique (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 property-ref. + + + + + not-null (opcional): Habilita la generació DDL de una restricción + de nulabilidad para las columnas. + + + + + optimistic-lock (opcional - por defecto a true): + 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). + + + + + + + typename puede ser: + + + + + + El nombre de un tipo básico Hibernate (por ejemplo, integer, string, character, + date, timestamp, float, binary, serializable, object, blob). + + + + + El nombre de una clase Java de tipo básico (por ejemplo, int, float, + char, java.lang.String, java.util.Date, java.lang.Integer, java.sql.Clob). + + + + + El nombre de una clase Java serializable. + + + + + El nombre de un tipo personalizado (por ejemplo, com.illflow.type.MyCustomType). + + + + + + 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 type. (Por ejemplo, para distinguir entre + Hibernate.DATE y Hibernate.TIMESTAMP, + o especificar un tipo personalizado.) + + + + El atributo access 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 + access="field", 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 org.hibernate.property.PropertyAccessor. + + + + 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 SELECT + en la consulta SQL que cargue una instancia: + + + ]]> + + + Observa que puedes referenciar la propia tabla de las entidades sin declarar un alias + o una columna particular (customerId en el ejemplo dado). Observa + además que puedes usar el elemento anidado de mapeo <formula> + si no te gusta usar el atributo. + + + + + + many-to-one + + + Una asociación ordinaria a otra clase persistente se declara usando + el elemento many-to-one. 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. + + + + + + + + + + + + + + + + + + + + + + + + ]]> + + + + name: El nombre de la propiedad. + + + + + column (opcional): El nombre de la columna clave foránea. + También puede ser especificado por uno o varios elementos anidados + <column>. + + + + + class (opcional - por defecto al tipo de la propiedad + determinado por reflección): El nombre de la clase asociada. + + + + + cascade (opcional): Especifica qué operaciones deben + ir en cascada desde el objeto padre al objeto asociado + + + + + fetch (opcional - por defecto a 1select): + Escoge entre recuperación outer-join o por selección secuencial. + + + + + update, insert (opcional - por defecto a true) + especifica que las columnas mapeadas deben ser incluídas en las sentencias SQL + UPDATE y/o INSERT. Establecer ambas a + false 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. + + + + + property-ref: (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. + + + + + access (opcional - por defecto a property): La + estrategia que Hibernate debe usar para acceder al valor de la propiedad. + + + + + unique (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 property-ref. + Esto hace efectivamente la multiplicidad de la asociación uno a uno. + + + + + not-null (opcional): Habilita la generación DDL de una + restricción de nulabilidad para las columnas de clave foránea. + + + + + optimistic-lock (opcional - por defecto a true): + 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. + + + + + lazy (opcional - por defecto a proxy): + Por defecto, las asociaciones de punto único van con proxies. + lazy="true" 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). + lazy="false" especifica que la asociación siempre será + recuperada tempranamente. + + + + + not-found (opcional - por defecto a exception): + Especifica cómo deben manejarse las claves foráneas que referencien + filas inexistentes: ignore tratará una fila perdida como + una asociación nula. + + + + + entity-name (opcional): El nombre de entidad de la clase + asociada. + + + + + formula (opcional): una expresión SQL que define el valor + para una clave foránea computada. + + + + + + + + Establecer el valor del atributo cascade a cualquier valor + significativo distinto de none propagará ciertas + operaciones al objeto asociado. Los valores significativos son los nombres de las + operaciones básicas de Hibernate, persist, merge, delete, save-update, + evict, replicate, lock, refresh, así como los valores especiales + delete-orphan y all y combinaciones de operaciones + separadas por coma, por ejemplo, cascade="persist,merge,evict" o + cascade="all,delete-orphan". Para una explicación completa, + ver . + + + + Una declaración típica muchos-a-uno se parece a esto: + + + ]]> + + + El atributo property-ref 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 Product tuviera un número + único serial que no es la clave primaria. (El atributo unique + controla la generación de DDL con la herramienta SchemaExport.) + + + ]]> + + + Entonces el mapeo para OrderItem debería usar: + + + ]]> + + + Sin embargo, esto no esta ciertamente alentado. + + + + Si la clave única referenciada abarca múltiples propiedades de la entidad asociada, + debes mapear las propiedades dentro de un elemento <properties>. + + + + + + one-to-one + + + Una asociación uno-a-uno a otra clase persistente se declara usando + un elemento one-to-one. + + + + + + + + + + + + + + + + ]]> + + + + name: El nombre de la propiedad. + + + + + class (opcional - por defecto al tipo de la propiedad + determinado por reflección): El nombre de la clase asociada. + + + + + cascade (opcional) especifica qué operaciones deben + ir en cascada desde el objeto padre al objeto asociado. + + + + + constrained (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 + save() y delete(), y determina cuándo + la asociación pueden ser virtualizados por proxies (es también usado por + la herramienta de exportación de esquemas). + + + + + fetch (opcional - por defecto select): + Elige entre recuperación outer-join o recuperación por consulta secuencial. + + + + + property-ref: (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. + + + + + access (opcional - por defecto a property): La + estrategia que Hibernate debe usar para acceder al valor de la propiedad. + + + + + formula (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 org.hibernate.test.onetooneformula). + + + + + lazy (opcional - por defecto a proxy): + Por defecto, las asociaciones de punto único van con proxies. + lazy="true" 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). + lazy="false" especifica que la asociación siempre será + recuperada tempranamente. Observa que si constrained="false", + la aplicación de proxies es imposible e Hibernate traerá temprano la + asociación! + + + + + + + Hay dos variedades de asociaciones uno-a-uno: + + + + asociaciones de clave primaria + + + asociaciones de clave foráneas única + + + + + 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 una asociación de clave primaria, añade los siguientes mapeos a + Employee y Person, respectivamente. + + + ]]> + ]]> + + + 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 foreign: + + + + + + employee + + + ... + +]]> + + + A una instancia recién salvada de Person se le asigna entonces + el mismo valor de clave primaria con que la instancia Employee + referida por la propiedad employee de esta Person. + + + + Alternativamente, una clave foránea con una restricción de unicidad, desde + Employee a Person, puede ser expresada como: + + + ]]> + + + Y esta asociación puede hacerse bidireccional agregando lo siguiente al mapeo de + Person : + + + ]]> + + + + + natural-id + + + + + ...... +]]> + + + 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 + <natural-id>. Hibernate generará las restricciones de clave + única y nulabilidad necesarias, y tu mapeo será más auto-documentado. + + + + Recomendamos fuertemente que implementes equals() y + hashCode() para comparar las propiedades de clave natural + de la entidad. + + + + Este mapeo no está concebido para usar con entidades con claves + primarias naturales. + + + + + + mutable (opcional, por defecto a false): + Por defecto, se asume que las propiedades de identificadores naturales son + inmutables (constantes). + + + + + + + + + component, dynamic-component + + + El elemento <component> 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". + + + + + + + + + + + + + + + + + + ........ +]]> + + + + name: El nombre de la propiedad. + + + + + class (opcional - por defecto al tipo de la propiedad + determinado por reflección): El nombre de la clase del componente (hijo). + + + + + insert: Aparecen las columnas mapeadas en + INSERTs SQL? + + + + + update: Aparecen las columnas mapeadas en + UPDATEs SQL? + + + + + access (opcional - por defecto a property): La + estrategia que Hibernate debe usar para acceder al valor de la propiedad. + + + + + lazy (opcional - por defecto a false): 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). + + + + + optimistic-lock (opcional - por defecto a true): + 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. + + + + + unique (opcional - por defecto a false): + Especifica que existe una restricción de unicidad sobre todas las + columnas mapeadas del componente. + + + + + + + Las etiquetas hijas <property> mapean propiedades de la + clase hija columnas de la tabla. + + + + El elemento <component> permite un subelemento + <parent> que mapea una propiedad de la clase del componente + como una referencia de regreso a la entidad contenedora. + + + + El elemento <dynamic-component> permite que un + Map sea mapeado como un componente, donde los nombres de + las propiedades se corresponden a las claves del mapa, ver . + + + + + + properties + + + El elemento <properties> 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 property-ref. Es también + una forma conveniente de definir una restricción de unicidad multicolumna. + + + + + + + + + + + + + + + ........ +]]> + + + + name: El nombre lógico del agrupamiento - + no un nombre de propiedad real. + + + + + insert: Aparecen las columnas mapeadas en + INSERTs SQL? + + + + + update: Aparecen las columnas mapeadas en + UPDATEs SQL? + + + + + optimistic-lock (opcional - por defecto a true): + 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. + + + + + unique (opcional - por defecto a false): + Especifica que existe una restricción de unicidad sobre todas las + columnas mapeadas del componente. + + + + + + + Por ejemplo, si tenemos el siguiente mapeo de <properties>: + + + + + ... + + + + + +]]> + + + Entonces puede que tengamos alguna asociación de datos heredados que se refiera + a esta clave única de la tabla de Person, en vez de la clave + primaria: + + + + + + +]]> + + + No recomendamos el uso de este tipo de cosas fuera del contexto del mapeo de + datos heredados. + + + + + + subclass + + + 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 + <subclass>. + + + + + + + + + + + + + ..... +]]> + + + + name: El nombre de clase cualificado completamente + de la subclase. + + + + + discriminator-value (opcional - por defecto al nombre de la clase): + Un valor que distingue a subclases individuales. + + + + + proxy (opcional): Especifica una clase o interface a usar para + proxies de inicialización perezosa. + + + + + lazy (opcional, por defecto a true): + Establecer lazy="false" deshabilita el uso de recuperación + perezosa. + + + + + + + Cada subclase debe declarar sus propias propiedades persistentes y subclases. + Se asume que las propiedades <version> y <id> + son heredadas de la clase raíz. Cada subclase en una jerarquía debe + definir un discriminator-value único. Si no se especifica ninguno, + se usa el nombre completamente cualificado de clase Java. + + + + Es posible definir mapeos subclass, union-subclass, + y joined-subclass en documentos de mapeo separados, directamente debajo + de hibernate-mapping. Esto te permite extender una jerarquía de clases + con sólo agregar un nuevo fichero de mapeo. Debes especificar un atributo + extends 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 información acerca de mapeos de herencia, ver . + + + + + + joined-subclass + + + 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 <joined-subclass>. + + + + + + + + + + + + + + + ..... +]]> + + + + name: El nombre de clase completamente cualificado de + la subclase. + + + + + table: El nombre de tabla de la subclase. + + + + + proxy (opcional): Especifica una clase o interface a + usar para proxies de inicializacón perezosa. + + + + + lazy (opcional, por defecto a true): + Establecer lazy="false" deshabilita el uso de recuperación + perezosa. + + + + + + + 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 <key>. El mapeo del comienzo del capítulo + debería ser reescrito como: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]]> + + + Para información acerca de mapeos de herencia, ver . + + + + + + union-subclass + + + 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 <class> 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 + <union-subclass>. + + + + + + + + + + + + + ..... +]]> + + + + name: El nombre de clase completamente cualificado de la subclase. + + + + + table: El nombre de tabla de la subclase. + + + + + proxy (optional): Especifica una clase o interface a + usar para proxies de inicializacón perezosa. + + + + + lazy (opcional, por defecto a true): + Establecer lazy="false" deshabilita el uso de recuperación + perezosa. + + + + + + + No se requiere columna o columna clave discriminadora para esta estrategia de mapeo. + + + + Para información acerca de mapeos de herencia, ver . + + + + + + join + + + Usando el elemento <join>, es posible mapear + propiedades de una clase a varias tablas. + + + + + + + + + + + + + + + + + ... +]]> + + + + + table: El nombre de la clase unida. + + + + + schema (opcional): Sobrescribe el nombre de esquema + especificado por el elemento raíz <hibernate-mapping>. + + + + + catalog (opcional): Sobrescribe el nombre de catálogo + especificado por el elemento raíz <hibernate-mapping>. + + + + + fetch (opcional - por defecto a join): + Si se establece a join, por defecto, Hibernate usará + una unión interior (inner join) para recuperar un <join> + definido por una clase o sus superclases y una unión externa (outer join) + para un <join> definido por una subclase. + Si se establece a select, entonces Hibernate usará una + select secuencial para un <join> 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 <join> definido por la clase y sus superclases. + + + + + inverse (opcional - por defecto a false): + De habilitarse, Hibernate no intentará insertar o actualizar las propiedades + definidas por esta unión. + + + + + optional (opcional - por defecto a false): + 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. + + + + + + + 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): + + + + + ... + + + + + + + + ...]]> + + + 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. + + + + + + key + + + Hasta ahora hemos visto el elemento <key> 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. + + + + + + + + + + + + ]]> + + + + + column (opcional): El nombre de columna de la clave foránea. + Puede ser también especificado por elemento(s) anidado(s) + <column>. + + + + + on-delete (opcional, por defecto a noaction): + Especifica si la restricción de clave foránea tiene el borrado en cascada + habilitado a nivel de base de datos. + + + + + property-ref (opcional): Especifica que la clave foránea + referencia columnas que no son del la clave primaria de la tabla original. + (Provisto para datos heredados.) + + + + + not-null (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). + + + + + update (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). + + + + + unique (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). + + + + + + + Recomendamos que, para los sistemas en donde el rendimiento sea importante, todas las + claves deben ser definidas on-delete="cascade", e Hibernate usará + una restricción ON CASCADE DELETE a nivel de base de datos, + en vez de muchas sentencias DELETE individuales. Ten en cuenta que + esta funcionalidad se salta la habitual estrategia de bloqueo optimista de Hibernate para + datos versionados. + + + + Los atributos not-null y update 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, debes declarar + la columna clave usando <key not-null="true">. + + + + + + los elementos column y formula + + Cualquier elemento de mapeo que acepte un atributo column aceptará + alternativamente un subelemento <column>. De forma similar, + <formula> es una alternativa al atributo formula. + + + ]]> + + expresión SQL]]> + + + Los atributos column y formula pueden + incluso ser combinados dentro del mismo mapeo de propiedad o asociación para + expresar, por ejemplo, condiciones de unión exóticas. + + + + + 'MAILING' +]]> + + + + + import + + + 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 + auto-import="true". Puedes incluso importar clases e interfaces que + no estén mapeadas explícitamente. + + + ]]> + + + + + + + ]]> + + + + class: El nombre de clase completamente cualificado de + cualquier clase Java. + + + + + rename (opcional - por defecto al nombre de clase sin cualificar): + Un nombre que será usado en el leguaje de consulta. + + + + + + + + + any + + + Hay un tipo más de mapeo de propiedad. El elemento de mapeo <any> + 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). + + + + El atributo meta-type 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 id-type. Debes especificar el + mapeo de valores del meta-type a nombres de clase. + + + + + + + + +]]> + + + + + + + + + + + + + + ..... + + + ..... +]]> + + + + name: el nombre de la propiedad. + + + + + id-type: el tipo del identificador. + + + + + meta-type (opcional - por defecto a string): + Cualquier tipo que sea permitido para un mapeo de discriminador. + + + + + cascade (opcional- por defecto a none): + el estilo de cascada. + + + + + access (opcional - por defecto a property): La + estrategia que Hibernate debe usar para acceder al valor de la propiedad. + + + + + optimistic-lock (opcional - por defecto a true): + 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. + + + + + + + + + + + Tipos de Hibernate + + + Entidades y Valores + + + Para entender el comportamiento de varios objetos a nivel de lenguaje Java + con respecto al servicio de persistencia, necesitamos clasificarlos en dos grupos: + + + + Una entidad 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 tratados en cascada 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. + + + + El estado persistente de una entidad consiste en referencias a otras entidades + e instancias de tipo valor. 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) son + 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. + + + + 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 componente + es una clase definida por el usuario con semántica de valor. + Una propiedad Java de tipo java.lang.String 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. + + + + Volveremos a visitar ambos conceptos a lo largo de la documentación. + + + + 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 <class>, + <subclass>, etc. Para los tipos de valor usamos + <property>, <component>, etc, + usualmente con un atributo type. El valor de este atributo + es el nombre de un tipo de mapeo 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. + + + + Todos los tipos prefabricados de Hibernate soportan semántica de nulos + excepto las colecciones. + + + + + + Tipos de valores básicos + + + Los tipos de mapeo básicos prefabricados pueden ser + categorizado a grandes rasgos en: + + + + integer, long, short, float, double, character, byte, + boolean, yes_no, true_false + + + Mapeos de tipos primitivos de Java o clases de envoltura a + la tipos de columna SQL (especícifica del vendedor). + boolean, yes_no y true_false + son codificaciones alternativas a boolean de + Java o java.lang.Boolean. + + + + + string + + + Un mapeo del tipo java.lang.String a + VARCHAR (u Oracle VAARCHAR2). + + + + + date, time, timestamp + + + Mapeos de tipo desde java.util.Date y sus subclases + a tipos SQL DATE, TIME y + TIMESTAMP (o equivalente). + + + + + calendar, calendar_date + + + Mapeos de tipo desde java.util.Date y sus subclases + a tipos SQL TIMESTAMP y DATE + (o equivalente). + + + + + big_decimal, big_integer + + + Mapeos de tipo desde java.math.BigDecimal y + java.math.BigInteger a NUMERIC + (o NUMBER de Oracle). + + + + + locale, timezone, currency + + + Mapeos de tipo desde java.util.Locale, + java.util.TimeZone y + java.util.Currency a + VARCHAR (o VARCHAR2 de Oracle). + Las instancias de Locale y Currency + son mapeadas a sus códigos ISO. Las instancias de + TimeZone son mapeadas a sus ID. + + + + + class + + + Un mapeo de tipo java.lang.Class a + VARCHAR (o VARCHAR2 de Oracle). + Una Class es mapeara a su nombre completamente + cualificado. + + + + + binary + + + Mapea arreglos de bytes a un tipo binario SQL apropiado. + + + + + text + + + Mapea cadenas largas Java al tipo SQL CLOB o + TEXT. + + + + + serializable + + + Mapea tipos serializables Java a un tipo binario SQL apropiado. + Puedes además indicar el tipo serializable + de Hibernate con el nombre de una clase o interface serializable Java + que no sea por defecto un tipo básico. + + + + + clob, blob + + + Mapeos de tipo para las clases JDBC java.sql.Clob y + java.sql.Blob. 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). + + + + + + + + + Los identificadores únicos de entidades y collecciones pueden ser de cualquier + tipo básico excepto binary, blob + y clob. + (Los identificadores compuestos están también permitidos, ver debajo.) + + + + Los tipos de valor básicos tienen sus constantes Type + correspondientes definidas en org.hibernate.Hibernate. Por ejemplo, + Hibernate.STRING representa el tipo string. + + + + + + Tipos de valor personalizados + + + Es relativamente fácil para los desarrolladores crear sus propios tipos de valor. + Por ejemplo, podrías querer persistir propiedades del tipo java.lang.BigInteger + a columnas VARCHAR. 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 + getName()/setName() de tipo java.lang.String + que fuera persistida a las columnas FIRST_NAME, INITIAL, + SURNAME. + + + + Para implementar un tipo personalizado, implementa bien org.hibernate.UserType + o org.hibernate.CompositeUserType y declara las propiedades usando el nombre + de clase completamente cualificado del tipo. Revisa org.hibernate.test.DoubleStringType + para ver qué tipo de cosas son posibles. + + + + + +]]> + + + Observa el uso de etiquetas <column> para mapear una propiedad + a múltiples columnas. + + + + Las interfaces CompositeUserType, EnhancedUserType, + UserCollectionType, y UserVersionType proveen + soporte a usos más especializados. + + + + Puedes incluso proveer de parámetros a un UserType en el + fichero de mapeo. Para hacer esto, tu UserType debe implementar + la interface org.hibernate.usertype.ParameterizedType. Para + proveer de parámetros a tu tipo personalizado, puedes usar el elemento + <type> en tus ficheros de mapeo. + + + + + 0 + +]]> + + + Ahora el UserType puede recuperar el valor del parámetro + llamado default del objeto Properties + que se le pasa. + + + + Si usas cierto UserType muy frecuentemente, puede ser útil + definir un nombre corto para é. Puedes hacer esto usando el elemento + <typedef>. 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. + + + + 0 +]]> + + ]]> + + + 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. + + + + Aunque el rico espectro de tipos prefabricados y soporte de componentes de Hibernate + significa que raramente necesites 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 + MonetaryAmount es una buena candidata para un + CompositeUserType, 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. + + + + + + + + Mapeando una clase más de una vez + + Es posible proveer más de un mapeo para una clase persistente en particular. En este caso debes + especificar un nombre de entidad 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. + + + + ... + + + + + + + + ... + +]]> + + + Observa cómo las asociaciones ahora se especifican usando entity-name en vez de + class. + + + + + + + identificadores SQL encomillados + + 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 Dialect SQL (usualmente comillas dobles, excepto corchetes + para SQL Server y backsticks para MySQL). + + + + + + ... +]]> + + + + + + Alternativas de metadatos + + + XML no es para todos, asá que hay algunas formas alternativas de definir metadatos de mapeo O/R + en Hibernate. + + + + Usando marcado de XDoclet + + + Muchos usuarios de Hibernate prefieren embeber la información de mapeo directamente + en el código fuente usando las @hibernate.etiquetas 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 + Cat con mapeos XDoclet. + + + + + + Para más ejemplos de XDoclet e Hibernate ver en el sitio web de Hibernate. + + + + + + Usando anotaciones JDK 5.0 + + 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 EntityManager del JSR-220 (la API de persistencia), y el soporte para + metadatos de mapeo está disponible vía el paquete Hibernate Annotations, + como una descarga por separado. Tanto metadatos de EJB3 (JSR-220) como de Hibernate3 están soportados. + + + + Este es un ejemplo de una clase POJO anotada como un bean de entidad EJB: + + + orders; + + // Getter/setter and business methods +}]]> + + + 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. + + + + + + + + + + diff --git a/documentation/manual/es-ES/src/main/docbook/content/batch.xml b/documentation/manual/es-ES/src/main/docbook/content/batch.xml new file mode 100644 index 0000000000..b24fbf2ce7 --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/content/batch.xml @@ -0,0 +1,192 @@ + + Procesamiento por lotes + + + Un enfoque ingenuo para insertar 100.000 filas en la base de datos usando Hibernate podría verse así: + + + + + + Esto podría caer sobre una OutOfMemoryException en algún sitio + cerca de la fila 50.000. Esto es porque Hibernate tiene en caché todas las instancias + de Customer recién instanciadas en el caché de nivel de sesión. + + + + 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): + + + + + + 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: + + + + + + Inserciones en lote + + + Al hacer persistentes objetos nuevos, debes limpiar con flush() y + llamar a clear() en la sesión regularmente, para controlar el tamaño + del caché de primer nivel. + + + + + + + + Actualizaciones en lote + + + Para recuperar y actualizar datos se aplican las mismas ideas. Adicionalmente, necesitas usar + scroll() para sacar ventaja de los cursores del lado del servidor en consultas + que devuelvan muchas filas de datos. + + + + + + + + update/delete en masa + + + 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 UPDATE y + DELETE 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 UPDATE y DELETE de SQL que se realizan + a través del Lenguaje de Consulta de Hibernate (Hibernate Query Language o + HQL). + + + + La pseudo-sintáxis para sentencias UPDATE y DELETE es: + ( UPDATE | DELETE ) FROM? ClassName (WHERE WHERE_CONDITIONS)?. Algunos puntos + a tener en cuenta: + + + + + + En la cláusula-from, la palabra clave FROM es opcional + + + + + Puede haber sólo una clase mencionada en la cláusula-from, y no puede + tener un alias. + + + + + 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. + + + + + La cláusula-where es también opcional. + + + + + + Como un ejemplo, para ejecutar un UPDATE HQL, usa el + método Query.executeUpdate(): + + + + + + Para ejecutar un DELETE HQL, usa el mismo método Query.executeUpdate() + (el método está nombrado para aquellos familiarizados con + PreparedStatement.executeUpdate() de JDBC): + + + + + + El valor int devuelto por el método Query.executeUpdate() + 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. + + + + 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. + + + + + diff --git a/documentation/manual/es-ES/src/main/docbook/content/best_practices.xml b/documentation/manual/es-ES/src/main/docbook/content/best_practices.xml new file mode 100644 index 0000000000..89bf4e2235 --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/content/best_practices.xml @@ -0,0 +1,229 @@ + + Mejores Prácticas + + + + Escribe clase finamente granularizadas y mapealas usando <component>. + + + Usa una clase Dirección para encapsular calle, + distrito, estado, código postal. + Esto alienta la reutilización de código y simplifica el refactoring. + + + + + Declara las propiedades identificadoras en clases persistentes. + + + 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). + + + + + Identifica las claves naturales. + + + Identifica las claves naturales de todas las entidades, y mapealas usando + <natural-id>. Implementa equals() y + hashCode() para comparar las propiedades que componen la clave natural. + + + + + Coloca cada mapeo de clase en su propio fichero. + + + No uses un solo documento monolítico de mapeo. Mapea com.eg.Foo en + el fichero com/eg/Foo.hbm.xml. Esto tiene sentido particularmente en un + ambiente de equipo. + + + + + Carga los mapeos como recursos. + + + Despliega los mapeos junto a las clases que mapean. + + + + + Considera externalizar las cadenas de consulta. + + + 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. + + + + + Usa variables de ligado. + + + 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. + + + + + No manejes tus propias conexiones JDBC. + + + 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 org.hibernate.connection.ConnectionProvider. + + + + + Considera usar un tipo personalizado. + + + 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 org.hibernate.UserType. Este enfoque libera al código de aplicación + de implementar transformaciones a / desde un tipo Hibernate. + + + + + Usa JDBC codificado a mano en cuellos de botella. + + + En áreas del sistema de rendimiento crítico, algunos tipos de operaciones podrían beneficiarse + del JDBC directo. Pero por favor, espero hasta que sepas 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 Session 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. + + + + + Comprende la limpieza (flushing) de Session. + + + 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. + + + + + En una aplicación en tres gradas, considera usar objetos separados. + + + 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 Session.merge() o Session.saveOrUpdate() para + sincronizar los objetos con la base de datos. + + + + + En una arquitectura en dos gradas, considera usar contexto de persistencia largos. + + + Las transacciones de base de datos tienen que ser tan cortas como sea posible. Sin embargo, + frecuentemente es necesario implementar transacciones de aplicación + 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. + + + + + No trates la excepciones como recuperables. + + + Esto es más una práctica necesaria que una "mejor" práctica. Cuando ocurra una excepción, + deshaz (rollback) la Transaction y cierra la Session. + 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 Session.load() + para determinar si una instancia con el identificador dado existe en la base de datos. En cambio, + usa Session.get() o una consulta. + + + + + Prefiere la recuperación perezosa para las asociaciones. + + + 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 lazy="false". + Cuando sea apropiada la recuperación por unión (join fetching) para un caso de uso en particular, + usa una consulta con un left join fetch. + + + + + + Usa el patrón sesión abierta en vista, o una fase de ensamblado + disciplinada para evitar problemas con datos no recuperados. + + + + Hibernate liberal al desarrollador de escribir Objetos de Transferencia de Datos + (Data Transfer Objects) (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. + + + + + Considera abstraer tu lógica de negocio de Hibernate + + + Oculta el código de acceso a datos (Hibernate) detrás de una interface. Combina los patrones + DAO y Sesión de Hebra Local. Incluso puedes tener + algunas clases hechas persistentes por JDBC escrito a mano, asociadas a Hibernate por medio + de un UserType. (Este consejo está pensado para aplicaciones "suficientemente + grandes"; ¡no es apropiado para una aplicación con cinco tablas!) + + + + + No uses mapeos de asociación exóticos. + + + 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. + + + + + Prefiere las asociaciones bidireccionales. + + + 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. + + + + + + + diff --git a/documentation/manual/es-ES/src/main/docbook/content/collection_mapping.xml b/documentation/manual/es-ES/src/main/docbook/content/collection_mapping.xml new file mode 100644 index 0000000000..21f28e6982 --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/content/collection_mapping.xml @@ -0,0 +1,1241 @@ + + Mapeo de Colecciones + + + Colecciones persistentes + + + Hibernate requiere que los campos valuados en colección + persistentes sean declarados como un tipo de interface, por ejemplo: + + + + + + La interface real podría ser java.util.Set, + java.util.Collection, java.util.List, + java.util.Map, java.util.SortedSet, + java.util.SortedMap o ... lo que te guste! + (Donde "lo que te guste" significa que tendrás que escribir una + implementación de org.hibernate.usertype.UserCollectionType.) + + + + Nota cómo hemos inicializado la variable de instancia de + HashSet. 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 persist(), por ejemplo - Hibernate realmente + remplazará el HashSet con una instancia de una + implementación de Set propia de Hibernate. + Observa errores como este: + + + + + + Las colecciones persistentes inyectadas por Hibernate se comportan + como HashMap, HashSet, + TreeMap, TreeSet o + ArrayList, dependiendo del tipo de interface. + + + + 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. + + + + 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). + + + + + + Mapeos de colección + + + El elemento de mapeo de Hibernate usado para mapear una colección + depende del tipo de la interface. Por ejemplom un elemento + <set> se usa para mapear propiedades de tipo + Set. + + + + + + + + +]]> + + + Aparte de <set>, existen además + los elementos de mapeo <list>, + <map>, <bag>, + <array> y <primitive-array>. + El elemento <map> es representativo: + + + + + + + + + + + + + + + + + + + + + + + +]]> + + + + name el nombre de la propiedad de colección + + + + + table (opcional - por defecto al nombre de la propiedad) + el nombre de la tabla de coleciión (no usado para asociaciones + uno-a-muchos) + + + + + schema (opcional) el nombre de un esquema de tablas + para sobrescribir el esquema declarado en el elemento raíz + + + + + lazy (opcional - por defecto a true) + puede ser usado para deshabilitar la recuperación perezosa y + especificar que la asociación es siempre recuperada tempranamente + (no disponible para arrays) + + + + + inverse (opcional - por defecto a false) + marca esta colección como el extremo "inverso" de una asociación + bidireccional. + + + + + cascade (opcional - por defecto a none) + habilita operaciones en cascada a entidades hijas + + + + + sort (opcional) especifica una colección + con ordenamiento natural, o una clase comparadora + dada + + + + + order-by (opcional, sólo JDK1.4) especifica una columna + de tabla (o columnas) que definen el orden de iteración del + Map, Set o bag, junto a un + asc o desc opcional. + + + + + where (opcional) especifica una condición + WHERE 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) + + + + + fetch (opcional, por defecto a select) + Elige entre recuperación por unión externa (outer-join), + recuperar por selección secuencial, y recuperación por + subselección secuencial. + + + + + batch-size (opcional, por defecto a 1) + especifica un "tamaño de lote" para la recuperar + perezosamente instancias de esta colección. + + + + + access (opcional - por defecto a property): + La estrategia que debe usar Hibernate para acceder al valor de la + propiedad. + + + + + optimistic-lock (opcional - por defecto a true): + 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.) + + + + + + + Claves foráneas de collección + + + 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 columna clave de + colección (o columnas) de la tabla de colección. + La columna clave de la colección es mapeada por el elemento + <key>. + + + + 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 not-null="true". + + + ]]> + + + La restricción de clave foránea puede usar + ON DELETE CASCADE. + + + ]]> + + + Mira el capítulo anterior por una definición completa del + elemento <key>. + + + + + + Elementos de collección + + + 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. + + + + Se hace referencia al tipo contenido como el tipo de elemento + de la colección. Los elementos de colección son + mapeados por <element> o + <composite-element>, o en el caso de referencias + de entidades, con <one-to-many> o + <many-to-many>. Las dos primeras mapean elementos + con semántica de valor, los dos siguientes son usados para mapear + asociaciones de entidades. + + + + + + Colecciones indexadas + + + Todos los mapeos de colección, excepto aquellos con semántica de + set o bag, necesitan una columna índice en la tabla + de colección, una columna que mapea a un índice de array, o + índice de List, o clave de Map. + El índice de un Map puede ser de cualquier tipo + básico, mapeado con <map-key>, o puede ser + una referencia de entidad, mapeada con <map-key-many-to-many>, + o puede ser un tipo compuesto, mapeado con <composite-map-key>. + El índice de un array o lista es siempre de tipo integer + y se mapea usando el elemento <list-index>. La columna + mapeada contiene enteros secuenciales (numerados desde cero, por defecto). + + + + + + + + ]]> + + + + column_name (requerido): El nombre de la columna que tiene + los valores índice de la colección. + + + + + base (opcional, por defecto a 0): El valor + de la columna índice que corresponde al primer elemento de la lista o + array. + + + + + + + + + + + + ]]> + + + + column (opcional): El nombre de la columna que tiene + los valores índice de la colección. + + + + + formula (opcional): Una fórmula SQL usada para + evaluar la clave del mapa. + + + + + type (requerido): el tipo de las claves del mapa. + + + + + + + + + + + + ]]> + + + + column (opcional): El nombre de la columna clave + foránea para los valores índice de la colección. + + + + + formula (opcional): Una fórmula SQL usada para + evaluar la clave foránea de la clave del mapa. + + + + + class (requerido): La clase de entidad usada como clave del mapa. + + + + + + + + Si tu tabla no tiene una columna índice, y deseas aún usar List como + tipo de propiedad, debes mapear la propiedad como un <bag> + de Hibernate. Un bag (bolsa) no retiene su orden al ser recuperado de la base de datos, + pero puede ser ordenado o clasificado opcionalmente. + + + + + + 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. + + + + Colecciones de valores y asociaciones muchos-a-muchos + + + Cualquier colección de valores o asociación muchos a muchos requiere una + tabla de colección dedicada con una columna o columnas + de clave foránea, columna de elemento de colección o + columnas y posiblemente una columna o columnas índice. + + + + Para una colección de valores, usamos la etiqueta <element>. + + + + + + + + + ]]> + + + + column (opcional): El nombre de la columna que tiene + los valores de los elementos de la colección. + + + + + formula (opcional): Una fórmula SQL usada para evaluar + el elemento. + + + + + type (requerido): El tipo del elemento de colección. + + + + + + + Una asociación muchos-a-muchos se especifica usando + el elemento <many-to-many>. + + + + + + + + + + + + + ]]> + + + + column (opcional): El nombre de la columna de clave + foránea del elemento. + + + + + formula (opcional): Una fórmula SQL opcional usada + para evaluar el valor de clave foránea del elemento. + + + + + class (requerido): El nombre de la clase asociada. + + + + + fetch (opcional - por defecto a join): + 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 SELECT) de una entidad y sus relaciones + muchos-a-muchos a otras entidades, deberías habilitar la recuperación + join no sólo de la colección misma, sino también con este + atributo en el elemento anidado <many-to-many>. + + + + + unique (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. + + + + + not-found (opcional - por defecto a exception): + Especifica cómo serán manejadas las claves foráneas que referencian + filas perdidas: ignore tratará una fila perdida como + una asociación nula. + + + + + entity-name (opcional): El nombre de entidad de la clase + asociada, como una alternativa a class. + + + + + + + Algunos ejemplos, primero, un conjunto de cadenas: + + + + + +]]> + + + Un bag conteniendo enteros (con un orden de iteración determinado por el + atributo order-by): + + + + + +]]> + + + Un array de entidades - en este caso, una asociación muchos a muchos: + + + + + + +]]> + + + Un mapa de índices de cadenas a fechas: + + + + + + +]]> + + + Una lista de componentes (discutidos en el próximo capítulo): + + + + + + + + + + +]]> + + + + + Asociaciones uno-a-muchos + + + Una asociación uno a muchos 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: + + + + + + Una instancia de la clase entidad contenida no puede pertenecer + a más de una instancia de la colección. + + + + + Una instancia de la clase entidad contenida no puede aparecer en más + de un valor del índice de colección. + + + + + + Una asociación de Product a Part requiere la + existencia de una columna clave foránea y posiblemente una columna índice a la tabla + Part. Una etiqueta <one-to-many> indica + que ésta es una asociación uno a muchos. + + + + + + + + + ]]> + + + + class (requerido): El nombre de la clase asociada. + + + + + not-found (opcional - por defecto a exception): + Especifica cómo serán manejados los identificadores en caché que referencien + filas perdidas: ignore tratará una fila perdida como una + asociación nula. + + + + + entity-name (opcional): El nombre de entidad de la clase + asociada, como una alternativa a class. + + + + + + + Observa que el elemento <one-to-many> no necesita + declarar ninguna columna. Ni es necesario especificar el nombre de table + en ningún sitio. + + + + Nota muy importante: Si la columna clave foránea de una asociación + <one-to-many> es declarada NOT NULL, debes + declarar el mapeo de <key> not-null="true" + o usar una asociación bidireccional con el mapeo de colección + marcado inverse="true". Ver la discusión sobre asociaciones + bidireccionales más adelante en este capítulo. + + + + Este ejemplo muestra un mapa de entidades Part por nombre + (donde partName es una propiedad persistente de Part). + Observa el uso de un índice basado en fórmula. + + + + + + +]]> + + + + + + Mapeos de colección avanzados + + + Colecciones ordenadas + + + Hibernate soporta colecciones implementando java.util.SortedMap y + java.util.SortedSet. Debes especificar un comparador en el fichero de + mapeo: + + + + + + + + + + + +]]> + + + Los valores permitidos del atributo sort son unsorted, + natural y el nombre de una clase que implemente + java.util.Comparator. + + + + Las colecciones ordenadas realmente se comportan como java.util.TreeSet o + java.util.TreeMap. + + + + Si quieres que la misma base de datos ordene los elementos de colección usa el + atributo order-by de los mapeos set, + bag o map. Esta solución está disponible sólo + bajo el JDK 1.4 o superior (está implementado usando LinkedHashSet o + LinkedHashMap). Esto realiza la ordenación en la consulta SQL, + no en memoria. + + + + + + + + + + + +]]> + + + Observa que el valor del atributo order-by es una ordenación SQL, no + una ordenación HQL! + + + + Las asociaciones pueden incluso ser ordenadas por algún criterio arbitrario en tiempo de + ejecución usando un filter() de colección. + + + + + + + + Asociaciones bidireccionales + + + Una asociación bidireccional permite la nevegación desde + ambos "extremos" de la asociación. Son soportados dos tipos de asociación + bidireccional: + + + + uno-a-muchos + + + set o bag valorados en un extremo, monovaluados al otro + + + + + muchos-a-muchos + + + set o bag valorados a ambos extremos + + + + + + + + + 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 inverse (cuál de ellos es tu + elección, pero no puede ser una colección indexada). + + + + 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: + + + + + ... + + + + + + + + + ... + + + + + + +]]> + + + Los cambios hechos sólo al extremo inverso de la asociación no + 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: + + + + + + El lado no-inverso se usa para salvar la representación en memoria a la base de datos. + + + + 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 inverse="true". + + + + + .... + + + + + + + + + .... + +]]> + + + Mapear un extremo de una asociación con inverse="true" no afecta + la operación de cascadas; éstos son conceptos ortogonales! + + + + + + Asociaciones bidireccionales con colecciones indexadas + + Requiere especial consideración una asociación bidireccional donde un extremo esté representado + como una <list> o <map>. Si hay una propiedad + de la clase hija que mapee a la columna índice, no hay problema, podemos seguir usando + inverse="true" en el mapeo de la colección: + + + + + .... + + + + + + + + + + .... + + +]]> + + + 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 + inverse="true". En cambio, podríamos usar el siguiente mapeo: + + + + + .... + + + + + + + + + + .... + +]]> + + + 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. + + + + + + Asociaciones ternarias + + + Hay tres enfoques posibles para mapear una asociación ternaria. + Una es usar un Map con una asociación como su índice: + + + + + + +]]> + + + + + +]]> + + + Un segundo enfoque es simplemente remodelar la asociación como una clase de entidad. + Este es el enfoque que usamos más comunmente. + + + + Una alternativa final es usar elementos compuestos, que discutiremos más adelante. + + + + + + <literal>Usando un <idbag></literal> + + + 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í podría 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. + + + + El elemento <idbag> te permite mapear una List + (o Collection) con semántica de bag. + + + + + + + + +]]> + + + Como puedes ver, un <idbag> 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. + + + + Observa que el rendimiento de actualización de un <idbag> es + mucho mejor que el de un <bag> regular! + Hibernate puede localizar filas individuales eficientemente y actualizarlas o borrarlas + individualmente, igual que si fuese una lista, mapa o conjunto. + + + + En la implementación actual, la estrategia de generación de identificador + native no está soportada para identificadores de colecciones + <idbag>. + + + + + + + + + + + + Ejemplos de colección + + + Las secciones previas son bastantes confusas. Así que miremos un ejemplo. + Esta clase: + + + + + + tiene una colección de instancias de Child. + Si cada hijo tiene como mucho un padre, el mapeo más natural es + una asociación uno-a-muchos: + + + + + + + + + + + + + + + + + + + + + +]]> + + + Esto mapea a las siguientes definiciones de tablas: + + + + + + Si el padre es requerido, usa una asociación bidireccional + uno-a-muchos: + + + + + + + + + + + + + + + + + + + + + + +]]> + + + Observa la restricción NOT NULL: + + + + + + Alternativamente, si absolutamente insistes que esta asociación debe ser unidireccional, + puedes declarar la restricción NOT NULL en el mapeo de + <key>: + + + + + + + + + + + + + + + + + + + + + +]]> + + + En la otra mano, si un hijo pudiera tener múltiples padres, sería apropiada + una asociación muchos-a-muchos: + + + + + + + + + + + + + + + + + + + + + +]]> + + + Definiciones de tabla: + + + + + + Para más ejemplos y un paseo completo a través del mapeo de relaciones padre/hijo, + ver . + + + + Son posibles mapeos de asociación aún más complejos. Catalogaremos todas las posibilidades + en el próximo capítulo. + + + + + diff --git a/documentation/manual/es-ES/src/main/docbook/content/component_mapping.xml b/documentation/manual/es-ES/src/main/docbook/content/component_mapping.xml new file mode 100644 index 0000000000..b62f726885 --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/content/component_mapping.xml @@ -0,0 +1,403 @@ + + Mapeo de Componentes + + + La noción de un componente es reusada en muchos contextos diferentes, + para propósitos diferentes, a través de Hibernate. + + + + Objetos dependientes + + + 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: + + + + + + + + Ahora Name puede ser persistido como un componente de + Person. Observa que Name define métodos + getter y setter para sus propiedades persistentes, pero no necesita declarar + ninguna interface ni propiedades identificadoras. + + + + Nuestro mapeo de Hibernate se vería así: + + + + + + + + + + + + +]]> + + + La tabla person tendría las columnas pid, + birthday, + initial, + first y + last. + + + + 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 ad hoc. + 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. + + + + Las propiedades de un componentes pueden ser de cualquier tipo de Hibernate + (colecciones, muchos-a-uno, asociaciones, otros componentes, etc). Los componentes + anidados no deben ser considerados un uso exótico. Hibernate está + concebido para soportar un modelo de objetos granularizado en fino. + + + + El elemento <component> permite un subelemento + <parent> que mapee una propiedad de la clase del componente + como una referencia de regreso a la entidad contenedora. + + + + + + + + + + + + + +]]> + + + + + Colecciones de objetos dependientes + + + Las colecciones de componentes están soportadas (por ejemplo, + un array de tipo Name). Declara tu colección + de componentes remplazando la etiqueta <element> + por una etiqueta <composite-element>. + + + + + + + + + +]]> + + + Nota: si defines un Set de elementos compuestos, es muy + importante implementar equals() y hashCode() + correctamente. + + + + Los elementos compuestos pueden contener componentes pero no colecciones. + Si tu elemento compuesto contiene a su vez componentes, usa la etiqueta + <nested-composite-element>. 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. + + + + Por favor observa que un mapeo de elemento compuesto no soporta + propiedades nulables si estás usando un <set>. + 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 + <list>, <map>, + <bag> o <idbag>. + + + + Un caso especial de un elemento compuesto es un elemento compuesto con un + elemento anidado <many-to-one>. 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 Order a Item donde + purchaseDate, price y + quantity son propiedades de la asociación: + + + + .... + + + + + + + + + +]]> + + + 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 Purchase puede + estar en el conjunto de una Order, pero no puede ser referenciada + por el Item al mismo tiempo. + + + Incluso son posibles las asociaciones ternarias (o cuaternarias, etc): + + + .... + + + + + + + +]]> + + + Los elementos compuestos pueden aparecer en consultas usando la misma + sintáxis que las asociaciones a otras entidades. + + + + + + Componentes como índices de Map + + + El elemento <composite-map-key> te permite mapear + una clase componente como la clave de un Map. Asegúrate que + sobrescribes hashCode() y equals() + correctamente en la clase componente. + + + + + Componentes como identificadores compuestos + + + Puedes usar un componente como un identidicador de una clase entidad. Tu clase + componente debe satisfacer ciertos requerimientos: + + + + + + Debe implementar java.io.Serializable. + + + + + Debe re-implementar equals() y + hashCode(), consistentemente con la + noción de base de datos de igualdad de clave compuesta. + + + + + + Nota: en Hibernat3, el segundo requerimiento no es absolutamente un + requerimiento rígido de Hibernate. Pero de todas formas, házlo. + + + + No puedes usar un IdentifierGenerator para generar claves + compuestas. La aplicación debe, en cambio, asignar sus propios identificadores. + + + + Usa la etiqueta <composite-id> (con elementos + anidados <key-property>) en lugar de la usual + declaración <id>. Por ejemplo, la clase + OrderLine tiene una clave primaria que depende de + la clave primaria (compuesta) de Order. + + + + + + + + + + + + + + + + + .... + +]]> + + + Ahora, cualquier clave foránea que referencie la tabla de OrderLine + es también compuesta. Debes declarar esto en tus mapeos de otras clases. Una asociación + a OrderLine sería mapeado así: + + + + + + + +]]> + + + (Nota que la etiqueta <column> es una alternativa al + atributo column en cualquier sitio.) + + + + Una asociación muchos-a-muchos a OrderLine + también usa la clave foránea compuesta: + + + + + + + + + +]]> + + + La colección de OrderLines en Order usaría: + + + + + + + + +]]> + + + (El elemento <one-to-many>, como es usual, no declara columnas.) + + + + Si OrderLine posee una colección por sí misma, tiene también + una clave foránea compuesta. + + + + .... + .... + + + + + + + + + ... + + +]]> + + + + + Componentes dinámicos + + + Puedes incluso mapear una propiedad de tipo Map: + + + + + + +]]> + + + La semántica de un mapeo <dynamic-component> es ídentica + a la de <component>. 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 + Configuration. + + + + + diff --git a/documentation/manual/es-ES/src/main/docbook/content/configuration.xml b/documentation/manual/es-ES/src/main/docbook/content/configuration.xml new file mode 100644 index 0000000000..3ae6d99d12 --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/content/configuration.xml @@ -0,0 +1,1761 @@ + + + Configuración + + + 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 hibernate.properties de ejemplo en + etc/ que muestra las diversas opciones. Tan sólo pon el + fichero de ejemplo en tu classpath y personalízalo. + + + + Configuración programática + + + Una instancia de org.hibernate.cfg.Configuration + representa un conjunto entero de mapeos de los tipos Java de una aplicación + a una base de datos SQL. La Configuration es usada para + construir una SessionFactory (inmutable). Los mapeos se + compilan de varios ficheros de mapeo XML. + + + + Puedes obtener una instancia de Configuration instanciándola + directamente y especificando documentos de mapeo XML. Si los ficheros de mapeo + están en el classpath, usa addResource(): + + + + + + Una forma alternativa (a veces mejor) es especificar la clase mapeada, + y dejar que Hibernate encuentre el documento de mapeo por ti: + + + + + + Entonces Hibernate buscará ficheros de mapeo llamados + /org/hibernate/auction/Item.hbm.xml y + /org/hibernate/auction/Bid.hbm.xml en el classpath. + Este enfoque elimina cualquier nombre de fichero en el código. + + + + Una Configuration también te permite especificar + propiedades de configuración: + + + + + + Esta no es la única forma de pasar propiedades de configuración + a Hibernate. La diversas opciones incluyen: + + + + + + Pasar una instancia de java.util.Properties a + Configuration.setProperties(). + + + + + Colocar hibernate.properties en un directorio + raíz del classpath. + + + + + Establecer propiedades System + usando java -Dproperty=value. + + + + + Incluir elementos <property> + en hibernate.cfg.xml (discutido luego). + + + + + + hibernate.properties es el enfoque más fácil + si quieres comenzar rápido. + + + + La Configuration está concebida como un objeto + de tiempo de arranque, para ser descartado una vez que una + SessionFactory es creada. + + + + + + Obteniendo una SessionFactory + + + Cuando todos los mapeos han sido parseados por la Configuration, + la aplicación debe obtener una fábrica de instancias de Session. + Esta fábrica está concebida para ser compartida por todas las hebras de + aplicación: + + + + + + Hibernate permite que tu aplicación instancie más de una + SessionFactory. Esto es útil si estás usando + más de una base de datos. + + + + + + Conexiones JDBC + + + Usualmente, quieres que la SessionFactory cree y almacene + en pool conexiones JDBC para ti. Si adoptas este enfoque, abrir una Session + es tan simple como: + + + + + + En cuanto hagas algo que requiera acceso a la base de datos, se obtendrá una + conexión JDBC del pool. + + + + 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 org.hibernate.cfg.Environment. + Describiremos ahora las configuraciones más importantes para la conexión + JDBC. + + + + Hibernate obtendrá (y tendrá en pool) conexiones usando + java.sql.DriverManager si configuras las siguientes propiedades: + + + + Propiedades JDBC de Hibernate + + + + + + Nombre de propiedad + Propósito + + + + + + hibernate.connection.driver_class + + + clase del driver jdbc + + + + + hibernate.connection.url + + + URL de jdbc + + + + + hibernate.connection.username + + + usuario de base de datos + + + + + hibernate.connection.password + + + contraseña del usuario de base de datos + + + + + hibernate.connection.pool_size + + + número máximo de conexiones manejadas por pooling + + + + +
+ + + El algoritmo de pooling de conexiones propio de Hibernate es sin embargo + algo rudimentario. Está concebido para ayudarte a comenzar y + no está concebido para usar en un sistema de producción + ni siquiera para pruebas de rendimiento. Debes usar un pool de terceros para + un mejor rendimiento y estabilidad. Sólo remplaza la propiedad + hibernate.connection.pool_size con configuraciones + específicas del pool de conexiones. Esto desactivará el pool + interno de Hibernate. Por ejemplo, podrías querer usar C3P0. + + + + C3P0 es un pool de conexiones JDBC de código abierto distribuido + junto a Hibernate en el directorio lib. + Hibernate usará su C3P0ConnectionProvider + para pooling de conexiones si estableces propiedades hibernate.c3p0.*. + Si quieres usar Proxool refiérete al hibernate.properties + empaquetado y al sitio web de Hibernate para más información. + + + + Aquí hay un fichero hibernate.properties de ejemplo para C3P0: + + + + + + Para su uso en un servidor de aplicaciones, casi siempre debes configurar + Hibernate para que obtenga conexiones de un Datasource + del servidor de aplicaciones registrado en JNDI. Necesitarás establecer + al menos una de las siguientes propiedades: + + + + Propiedades de Datasource de Hibernate + + + + + + Nombre de propiedad + Propósito + + + + + + hibernate.connection.datasource + + + nombre del datasource JNDI + + + + + hibernate.jndi.url + + + URL del provedor JNDI (optional) + + + + + hibernate.jndi.class + + + clase de la InitialContextFactory de JNDI (opcional) + + + + + hibernate.connection.username + + + usuario de base de datos (opcional) + + + + + hibernate.connection.password + + + contraseña del usuario de base de datos (opcional) + + + + +
+ + + He aquí un fichero hibernate.properties de ejemplo + para un un datasource JNDI provisto por un servidor de aplicaciones. + + + + + + Las conexiones JDBC obtenidas de un datasource JNDI participarán automáticamente + en las transacciones del servidor de aplicaciones manejadas por contenedor. + + + + Pueden darse propiedades de conexión arbitrarias anteponiendo + "hibernate.connnection" al nombre de propiedad. + Por ejemplo, puedes especificar un charSet usando + hibernate.connection.charSet. + + + + Puedes definir tu propia estrategia de plugin para obtener conexiones JDBC implementando + la interface org.hibernate.connection.ConnectionProvider. Puedes + seleccionar una implementación personalizada estableciendo + hibernate.connection.provider_class. + + +
+ + + Parámetros de configuración opcionales + + + 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. + + + + Advertencia: algunas de estas propiedades son de "nivel-de-sistema" + solamente.. Las propiedades a nivel de sistema sólo pueden ser + establecidas por medio de java -Dproperty=value o + hibernate.properties. No pueden + establecerse por medio de las otras técnicas arriba descritas. + + + + Propiedades de Configuración de Hibernate + + + + + + Nombre de propiedad + Propósito + + + + + + hibernate.dialect + + + El nombre de clase de un Dialect + de Hibernate que permite a Hibernate generar SQL optimizado + para una base de datos relacional en particular. + + ej. + full.classname.of.Dialect + + + + + + hibernate.show_sql + + + Escribe todas las sentencias SQL a la consola. + + ej. + true | false + + + + + + hibernate.default_schema + + + Cualifica, en el SQL generado, los nombres de tabla sin cualificar + con el esquema/tablespace dado. + + ej. + SCHEMA_NAME + + + + + + hibernate.default_catalog + + + Cualifica, en el SQL generado, los nombres de tabla sin cualificar + con el catálogo dado. + + ej. + CATALOG_NAME + + + + + + hibernate.session_factory_name + + + La SessionFactory será + ligada a este nombre en JNDI automáticamente + después de ser creada. + + ej. + jndi/composite/name + + + + + + hibernate.max_fetch_depth + + + 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 0 deshabilita la recuperación + por outer join por defecto. + + ej. + valores recomendados entre 0 y + 3 + + + + + + hibernate.default_batch_fetch_size + + + Establece un tamaño por defecto para la recuperación + en lote de asociaciones de Hibernate. + + ej. + valores recomendados 4, 8, + 16 + + + + + + hibernate.default_entity_mode + + + Establece un modo por defecto de representación de + entidades para todas las sesiones abiertas por esta + SessionFactory + + dynamic-map, dom4j, + pojo + + + + + + hibernate.order_updates + + + 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. + + ej. + true | false + + + + + + hibernate.generate_statistics + + + De habilitarse, Hibernate colectará estadísticas + útiles para la afinación de rendimiento. + + ej. + true | false + + + + + + hibernate.use_identifer_rollback + + + De habilitarse, las propiedades identificadoras + generadas serán reseteadas a valores por + defecto cuando los objetos sean borrados. + + ej. + true | false + + + + + + hibernate.use_sql_comments + + + De activarse, Hibernate generará comentarios dentro del SQL, + para una más fácil depuración, por defecto a + false. + + ej. + true | false + + + + + +
+ + + Propiedades de JDBC y Conexiones de Hibernate + + + + + + Nombre de propiedad + Propoósito + + + + + + hibernate.jdbc.fetch_size + + + Un valor distinto de cero que determina el tamaño + de recuperación de JDBC (llama a + Statement.setFetchSize()). + + + + + hibernate.jdbc.batch_size + + + Un valor distinto de cero habilita el uso de actualizaciones + en lote de JDBC2 por Hibernate. + + ej. + valores recomendados entre 5 y 30 + + + + + + hibernate.jdbc.batch_versioned_data + + + Establece esta propiedad a true si tu driver JDBC + devuelve cuentas correctas de filas desde executeBatch() + (usualmente es seguro activar esta opción). Hibernate usará + DML en lote para versionar automáticamente los datos. + Por defecto a false. + + ej. + true | false + + + + + + hibernate.jdbc.factory_class + + + Selecciona un Batcher personalizado. + La mayoría de las aplicaciones no necesitarán + esta propiedad de configuración. + + ej. + classname.of.BatcherFactory + + + + + + hibernate.jdbc.use_scrollable_resultset + + + 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. + + ej. + true | false + + + + + + hibernate.jdbc.use_streams_for_binary + + + Usa flujos (streams) al escribir/leer tipos + binary o serializable + a/desde JDBC (propiedad a nivel de sistema). + + ej. + true | false + + + + + + hibernate.jdbc.use_get_generated_keys + + + Habilita el uso de PreparedStatement.getGeneratedKeys() + 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. + + ej. + true|false + + + + + + hibernate.connection.provider_class + + + EL nombre de clase de un ConnectionProvider personalizado + que provea conexiones JDBC a Hibernate. + + ej. + classname.of.ConnectionProvider + + + + + + hibernate.connection.isolation + + + Establece el nivel de aislamiento de transacción JDBC. + Comprueba java.sql.Connection para valores + significativos pero observa que la mayoría de las bases de + datos no soportan todos los niveles de aislamiento. + + eg. + 1, 2, 4, 8 + + + + + + hibernate.connection.autocommit + + + Habilita compromiso automático (autocommit) para + las conexiones JDBC en pool (no recomendado). + + ej. + true | false + + + + + + hibernate.connection.release_mode + + + 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 after_statement + 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 + after_transaction. auto eligirá + after_statement para las estrategias JTA o CMT + de transacción y after_transaction para la + estrategia JDBC de transacción. + + ej. + on_close (por defecto)| after_transaction | + after_statement | auto + + + + + + hibernate.connection.<propertyName> + + + Pasa la propiedad JDBC propertyName + a DriverManager.getConnection(). + + + + + hibernate.jndi.<propertyName> + + + Pasa la propiedad propertyName + a InitialContextFactory de JNDI. + + + + +
+ + + Propiedades de Caché de Hibernate + + + + + + Nombre de propiedad + Propósito + + + + + + hibernate.cache.provider_class + + + El nombre de clase de un CacheProvider personalizado. + + ej. + classname.of.CacheProvider + + + + + + hibernate.cache.use_minimal_puts + + + 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. + + ej. + true|false + + + + + + hibernate.cache.use_query_cache + + + Habilita el caché de lectura, consultas individuales todavía + tienen que ponerse cachables. + + ej. + true|false + + + + + + hibernate.cache.use_second_level_cache + + + Puede ser usado para deshabilitar completamente el caché + de segundo nivel, que está habilitado por defecto para clases + que especifican un mapeo <cache>. + + ej. + true|false + + + + + + hibernate.cache.query_cache_factory + + + El nombre de clase de una interface QueryCache + personalizada, por defecto al StandardQueryCache + prefabricado. + + ej. + classname.of.QueryCache + + + + + + hibernate.cache.region_prefix + + + Un prefijo a usar para los nombres de región + del caché de segundo nivel. + + ej. + prefix + + + + + + hibernate.cache.use_structured_entries + + + Fuerza a Hibernate a almacenar los datos en el caché + de segundo nivel en un formato más amigable al humano. + + ej. + true|false + + + + + +
+ + + Propiedades de Transacción de Hibernate + + + + + + Nombre de propiedad + Propósito + + + + + + hibernate.transaction.factory_class + + + El nombre de clase de un TransactionFactory + a usar con la API de Transaction de Hibernate + (por defectoa JDBCTransactionFactory). + + ej. + classname.of.TransactionFactory + + + + + + jta.UserTransaction + + + Un nombre JNDI usado por JTATransactionFactory para + obtener la UserTransaction JTA del servidor + de aplicaciones. + + ej. + jndi/composite/name + + + + + + hibernate.transaction.manager_lookup_class + + + El nombre de clase de un TransactionManagerLookup + requerido cuando el chaché a nivel de JVM está + habilitado o cuando se usa un generador alto/bajo en un + entorno JTA. + + ej. + classname.of.TransactionManagerLookup + + + + + + hibernate.transaction.flush_before_completion + + + 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). + + ej. + true | false + + + + + + hibernate.transaction.auto_close_session + + + 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). + + ej. + true | false + + + + + +
+ + + Propiedades Misceláneas + + + + + + Nombre de propiedad + Propósito + + + + + + hibernate.query.factory_class + + + Elige la implementación de parser HQL. + + ej. + org.hibernate.hql.ast.ASTQueryTranslatorFactory or + org.hibernate.hql.classic.ClassicQueryTranslatorFactory + + + + + + hibernate.query.substitutions + + + Mapeos de símbolos en consultas Hibernate a + símbolos SQL. (los símbolos puedem ser + nombres de función o literales, por ejemplo). + + ej. + hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC + + + + + + hibernate.hbm2ddl.auto + + + Exporta automáticamente DDL de esquema cuando + al crear la SessionFactory. + Con create-drop, el esquema de + base de datos será desechado cuando la + SessionFactory se cierre explícitamente. + + ej. + update | create | create-drop + + + + + + hibernate.cglib.use_reflection_optimizer + + + 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 + hibernate.cfg.xml. + + ej. + true | false + + + + + +
+ + + SQL Dialects + + + You should always set the hibernate.dialect property to the correct + org.hibernate.dialect.Dialect 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. + + + + Dialectos SQL de Hibernate(<literal>hibernate.dialect</literal>) + + + + + + RDBMS + Dialecto + + + + + DB2 org.hibernate.dialect.DB2Dialect + + + DB2 AS/400 org.hibernate.dialect.DB2400Dialect + + + DB2 OS390 org.hibernate.dialect.DB2390Dialect + + + PostgreSQL org.hibernate.dialect.PostgreSQLDialect + + + MySQL org.hibernate.dialect.MySQLDialect + + + MySQL con InnoDB org.hibernate.dialect.MySQLInnoDBDialect + + + MySQL con MyISAM org.hibernate.dialect.MySQLMyISAMDialect + + + Oracle (cualquier versión) org.hibernate.dialect.OracleDialect + + + Oracle 9i/10g org.hibernate.dialect.Oracle9Dialect + + + Sybase org.hibernate.dialect.SybaseDialect + + + Sybase Anywhere org.hibernate.dialect.SybaseAnywhereDialect + + + Microsoft SQL Server org.hibernate.dialect.SQLServerDialect + + + SAP DB org.hibernate.dialect.SAPDBDialect + + + Informix org.hibernate.dialect.InformixDialect + + + HypersonicSQL org.hibernate.dialect.HSQLDialect + + + Ingres org.hibernate.dialect.IngresDialect + + + Progress org.hibernate.dialect.ProgressDialect + + + Mckoi SQL org.hibernate.dialect.MckoiDialect + + + Interbase org.hibernate.dialect.InterbaseDialect + + + Pointbase org.hibernate.dialect.PointbaseDialect + + + FrontBase org.hibernate.dialect.FrontbaseDialect + + + Firebird org.hibernate.dialect.FirebirdDialect + + + +
+ +
+ + + Recuperación por Unión Externa (Outer Join Fetching) + + + Si tu base de datos soporta uniones externas del estilo ANSI, Oracle o Sybase, la + recuperación por unión externa 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 SELECT SQL. + + + + La recuperación por unión externa puede ser deshabilitada + globalmente estableciendo la propiedad + hibernate.max_fetch_depth a 0. + Un valor de 1 o mayor habilita la recuperación + por unión externa para asociaciones uno-a-uno y muchos-a-uno que + hayan sido mapeadas con fetch="join". + + + + Ver para más información. + + + + + + Flujos Binarios + + + Oracle limita el tamaño de arrays de byte + que puedan ser pasados a/desde su driver JDBC. Si deseas usar instancias + grandes de tipo binary o serializable, + debes habilitar hibernate.jdbc.use_streams_for_binary. + Esta es una propiedad a nivel de sistema solamente. + + + + + + Caché de segundo nivel y de lectura + + + Las propiedades prefijadas por hibernate.cache + te permiten usar un sistema de caché de segundo nivel + en el ámbito de un proceso o cluster con Hibernate. + Ver para más detalles. + + + + + + Sustitución de Lenguaje de Consulta + + + Puedes definir nuevos símbolos de consulta de Hibernate usando + hibernate.query.substitutions. Por ejemplo: + + + hibernate.query.substitutions true=1, false=0 + + + causaría que los símbolos true y false sean + traducidos a literales enteros en el SQL generado. + + + hibernate.query.substitutions toLowercase=LOWER + + + te permitiría renombrar la función LOWER de SQL. + + + + + + Hibernate statistics + + + Si habilitas hibernate.generate_statistics, Hibernate + expondrá un número de métricas que son útiles + al afinar un sistema en ejecución vía + SessionFactory.getStatistics(). Hibernate puede incluso ser + configurado para exponer estas estadísticas vía JMX. Lee el + Javadoc de las interfaces en org.hibernate.stats + para más información. + + + +
+ + + Registros de mensajes (Logging) + + + Hibernate registra varios eventos usando commons-logging + de Apache. + + + + El servicio de commons-logging saldrá directamente ya sea a + Log4J (si incluyes log4j.jar in your classpath) o + JDK1.4 logging (al ejecutar bajo JDK1.4 o superior). Puedes descargar + Log4J desde http://logging.apache.org. Para usar + Log4J necesitarás colocar un fichero log4j.properties + en tu classpath. Un fichero de propiedades de ejemplo se distribuye con + Hibernate en el directorio src/. + + + + 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: + + + + Categorías de Registro de Hibernate + + + + + + Categoría + Función + + + + + org.hibernate.SQL + Registra todas las sentencias DML de SQL a + medida que se ejecutan + + + org.hibernate.type + Registra todos los parámetros JDBC + + + org.hibernate.tool.hbm2ddl + Registra todas las sentencias DDL de SQL a + medida que se ejecutan + + + org.hibernate.pretty + + Registra el estado de todas las entidades (máximo + de 20 entidades) asociadas con la sesión en tiempo + de limpieza (flush) + + + + org.hibernate.cache + Registra toda la actividad del caché de segundo nivel + + + org.hibernate.transaction + Registra la actividad relacionada con la transacción + + + org.hibernate.jdbc + Registra toda adquisición de recursos JDBC + + + org.hibernate.hql.ast + Regista los ASTs de HQL y SQL, así como + otra información sobre análisis de consultas. + + + org.hibernate.secure + Registra todas las peticiones de autorización JAAS + + + org.hibernate + + Registra todo (mucha información, pero muy útil + para la resolución de problemas) + + + + +
+ + + Al desarrollar aplicacinoes con Hibernate, casi siempre debes trabajar con + debug habilitado para la categoría org.hibernate.SQL + o, alternativamente, la propiedad hibernate.show_sql habilitada. + + + +
+ + + Implementando una <literal>NamingStrategy</literal> + + + La interface org.hibernate.cfg.NamingStrategy te permite + especificar un "estándar de nombrado" para objetos de la base de datos + y elementos de esquema. + + + + 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 TBL_, por ejemplo). La estrategia por defecto + usada por Hibernate mínima en absoluto. + + + + Puedes especificar una estrategia diferente llamando a + Configuration.setNamingStrategy() antes de agregar los mapeos: + + + + + + org.hibernate.cfg.ImprovedNamingStrategy + es una estrategia prefabricada que puede ser un punto de + partida útil para algunas aplicaciones. + + + + + + Fichero de configuración XML + + + Un enfoque alternativo de configuración es especificar una + configuración completa en un fichero llamado hibernate.cfg.xml. + Este fichero puede ser usado como un remplazo del fichero hibernate.properties o, + si ambos están presentes, para sobrescribir propiedades. + + + + El fichero de configuración XML se espera por defecto en la + raíz o tu CLASSPATH. He aquí un ejemplo: + + + + + + + + + + + + java:/comp/env/jdbc/MyDB + org.hibernate.dialect.MySQLDialect + false + + org.hibernate.transaction.JTATransactionFactory + + java:comp/UserTransaction + + + + + + + + + + + + +]]> + + + Como puedes ver, la ventaja de este enfoque es la externalización de los + nombres de los fichero de mapeo a configuración. El + hibernate.cfg.xml es también más conveniente + una vez que hayas afinado el caché de Hibernate. Observa que elección + tuya usar ya sea hibernate.properties o + hibernate.cfg.xml, ambos son equivalentes, excepto por los + beneficios de usar la sintaxis XML arriba mencionados. + + + + Con la configuración XML, arrancar Hibernate es tan simple como + + + + + + Puedes tomar un fichero XML diferente usando + + + + + + + + Integració con Servidores de Aplicaciones J2EE + + + Hibernate tiene los siguientes puntos de integración con la + infraestructura J2EE: + + + + + + Datasources manejados por contenedor: Hibernate puede usar + conexiones JDBC manejadas por el contenedor y provistas a través de JNDI. + Usualmente, un TransactionManager compatible con JTA y un + ResourceManager 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 Transaction de Hibernate para + mantener tu código portable. + + + + + + + + Ligamento Automático JNDI: Hibernate puede ligar sus + SessionFactory a JNDI después del arranque. + + + + + + + + Ligamento de Sesión JTA: + La Session de Hibernate puede ser ligada automáticamente + al ámbito de transacciones JTA si usas EJBs. Simplemente busca la + SessionFactory de JNDI y obtén la Session + actual. Deja que Hibernate cuide de limpiar y cerrar la Session + cuando se complete tu transacción JTA. La demarcación de transacción + es declarativa, en descriptores de despliegue de EJB. + + + + + + + + Despliegue JMX: 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 SessionFactory desde una Configuration. + El contenedor arrancará tu HibernateService, e idealmente también + cuidará de las dependencias entre servicios (El datasource debe estar + disponible antes que arranque Hibernate, etc). + + + + + + Dependiendo de tu entorno, podrías tener que establecer la opción + de configuración hibernate.connection.aggressive_release + a true si tu servidor de aplicaciones muestra excepciones "connection containment". + + + + Configuración de la estrategia de transacción + + + La API de Session 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 UserTransaction cuando sea necesario. + + + + Para mantener tu código portable entre estos dos (y otros) entornos recomendamos la API + de Transaction de Hibernate, que envuelve y oculta el sistema subyacente. + Tienes que especificar una clase fábrica para las instancias de Transaction + estableciendo la propiedad de configuración hibernate.transaction.factory_class + de Hibernate. + + + + Hay tres elecciones estándar (prefabricadas): + + + + + org.hibernate.transaction.JDBCTransactionFactory + + delega a transacciones de base de datos (JDBC) (por defecto) + + + + org.hibernate.transaction.JTATransactionFactory + + + 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. + + + + + org.hibernate.transaction.CMTTransactionFactory + + delega a transacciones JTA manejadas por contenedor + + + + + + Puedes definir también tus propias estrategias de transacción + (para un servicio de transacción CORBA, por ejemplo). + + + + Algunas funcionalidades en Hibernate (ej, el caché de segundo nivel, ligamento + automático de JTA y Session, etc.) requieren acceso al TransactionManager + de JTA en un entorno manejado. En un servidor de aplicaciones tienes que especificar + cómo Hibernate debe obtener una referencia al TransactionManager, + pues J2EE no estandariza un solo mecanismo: + + + + TransactionManagers de JTA + + + + + + Transaction Factory + Servidor de Aplicaciones + + + + + org.hibernate.transaction.JBossTransactionManagerLookup + JBoss + + + org.hibernate.transaction.WeblogicTransactionManagerLookup + Weblogic + + + org.hibernate.transaction.WebSphereTransactionManagerLookup + WebSphere + + + org.hibernate.transaction.WebSphereExtendedJTATransactionLookup + WebSphere 6 + + + org.hibernate.transaction.OrionTransactionManagerLookup + Orion + + + org.hibernate.transaction.ResinTransactionManagerLookup + Resin + + + org.hibernate.transaction.JOTMTransactionManagerLookup + JOTM + + + org.hibernate.transaction.JOnASTransactionManagerLookup + JOnAS + + + org.hibernate.transaction.JRun4TransactionManagerLookup + JRun4 + + + org.hibernate.transaction.BESTransactionManagerLookup + Borland ES + + + +
+ +
+ + + <literal>SessionFactory</literal> ligada a JNDI + + + Una SessionFactory de Hibernate ligada a JNDI puede simplificar + la obtención de la fábrica y la creación de nuevas + Sessions. Observa que esto no está relacionado a un + Datasource ligado a JNDI, simplemente ambos usan el mismo + registro! + + + + Si deseas tener la SessionFactory ligada a un espacio de nombres de JNDI, + especifica un nombre (ej. java:hibernate/SessionFactory) usando la + propiedad hibernate.session_factory_name. Si esta propiedad es omitida, + la SessionFactory no será ligada a JNDI (Esto es especialmente + útil en entornos con una implementació JNDI de sólo lectura por defecto, + ej. Tomcat.) + + + + Al ligar la SessionFactory a JNDI, Hibernate usará los valores de + hibernate.jndi.url, hibernate.jndi.class para instanciar + un contexto inicial. Si étos no se especifican, se usará el + InitialContext por defecto. + + + + Hibernate colocará automáticamente la SessionFactory + en JNDI después que llames a cfg.buildSessionFactory(). + 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 HibernateService (discutido luego). + + + + Si usas una SessionFactory de JNDI, un EJB o cualquier otra + clase puede obtener la SessionFactory usando una búsqueda + JNDI. Observa que esta configuración no es necesaria si usas la clase de ayuda + HibernateUtil introducida en el capítulo uno, que actúa + como un registro Singleton. Sin embargo, HibernateUtil es más + común en un entorno no manejado. + + + + + + Ligado automático de JTA y Session + + + Para entornos no manejados hemos sugerido HibernateUtil con una + SessionFactory estática, y administración de la + Session 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 SessionFactory + a JNDI en un entorno manejado. + + + + En vez de rodar tu propia utilidad de ThreadLocal, + usa el método getCurrentSession() en la + SessionFactory para obtener una Session + de Hibernate. Si no hubiese una Session de Hibernate en la + transacción JTA actual, se arrancará y asignará una. + Ambas opciones de configuración hibernate.transaction.flush_before_completion + y hibernate.transaction.auto_close_session, serán establecidas + automáticamente para cada Session que obtengas con + getCurrentSession(), de modo que éstas serán + limpiadas (flushed) y cerradas automáticamente cuando el contenedor complete + las transacciones JTA. + + + + Si tu, por ejemplo, usas el patrón de diseño DAO para escribir tu + capa de persistencia, todos los DAO's buscan la SessionFactory + cuando se necesite y abren la sesión "actual". No hay necesidad de pasar + las instancias de SessionFactory o Session + alrededor entre el código de control y el código DAO. + + + + + + Despliegue JMX + + + La línea cfg.buildSessionFactory() todavía tiene + que ser ejecutada en algun sitio para obtener una SessionFactory + en JNDI. Puedes hacer esto bien en un bloque inicializador static + (como aquel en HibernateUtil) o bien despliegas Hibernate como un + servicio manejado. + + + + Hibernate se distribuye con org.hibernate.jmx.HibernateService + 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 jboss-service.xml de ejemplo para JBoss 4.0.x: + + + + + + + + + jboss.jca:service=RARDeployer + jboss.jca:service=LocalTxCM,name=HsqlDS + + + java:/hibernate/SessionFactory + + + java:HsqlDS + org.hibernate.dialect.HSQLDialect + + + + org.hibernate.transaction.JTATransactionFactory + + org.hibernate.transaction.JBossTransactionManagerLookup + true + true + + + 5 + + + true + org.hibernate.cache.EhCacheProvider + true + + + true + + + auction/Item.hbm.xml,auction/Category.hbm.xml + + + +]]> + + + Este fichero es desplegado en un directorio llamado META-INF y + empaquetado en un fichero JAR con la extensión .sar + (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. + + + + +
+ +
+ diff --git a/documentation/manual/es-ES/src/main/docbook/content/events.xml b/documentation/manual/es-ES/src/main/docbook/content/events.xml new file mode 100644 index 0000000000..c5a70dfd3b --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/content/events.xml @@ -0,0 +1,233 @@ + + Interceptores y eventos + + + 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. + + + + Interceptores + + + La interface Interceptor 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 Interceptor establece + automáticamente el createTimestamp cuando un Auditable es + creado y actualiza la propiedad lastUpdateTimestamp cuando un + Auditable es acutalizado. + + + + + + El interceptor podría ser especificado cuando se crea la sesión: + + + + + + Puedes además establecer un interceptor a un nivel global, usando la Configuration: + + + + + + + + Sistema de eventos + + + Si tienes que reaccionar a eventos particulares en tu capa de persistencia, puedes también la + arquitectura de eventos de Hibernate3. El sistema de eventos puede ser usado + en adición o como un remplazo a los interceptores. + + + + Esencialmente todos los métodos de la interface Session se correlacionan + con un evento. Tienes un LoadEvent, un FlushEvent, etc + (consulta el DTD del fichero de configuración XML o el paquete org.hibernate.event + para la lista completa de tipos de evento definidos). Cuando se hace una petición de uno de estos + métodos, la Session 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 + LoadEvent es procesado por la implementación registrada de la interface + LoadEventListener), en cuyo caso su implementación sería responsable + de procesar cualquier petición load() hecha a la Session. + + + + 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. + + + + 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 + Configuration, 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: + + + + + + Necesitas además una entrada de configuración diciéndole a Hibernate que use el + oyente en vez del oyente por defecto: + + + + + ... + + +]]> + + + En cambio, puedes registrarlo programáticamente: + + + + + + Los oyentes registrados declarativamente no pueden compartir instancias. Si el mismo nombre de clase es + usado en múltiples elementos <listener/>, 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. + + + + ¿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. + + + + + + Seguridad declarativa de Hibernate + + 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. + + + + Primero, debes configurar los oyentes de eventos apropiados, para habilitar el uso de + autorización JAAS. + + + + + +]]> + + + Seguido, aún en hibernate.cfg.xml, liga los permisos a roles: + + + +]]> + + + Los nombres de role son los roles entendidos por tu proveedor de JACC. + + + + + + diff --git a/documentation/manual/es-ES/src/main/docbook/content/example_mappings.xml b/documentation/manual/es-ES/src/main/docbook/content/example_mappings.xml new file mode 100644 index 0000000000..1ac017b185 --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/content/example_mappings.xml @@ -0,0 +1,654 @@ + + Ejemplo: Varios Mapeos + + + Este capítulo muestra mapeos de asociaciones más complejos. + + + + Empleador/Empleado + + + El siguiente modelo de la relación entre Employer y Employee + usa una clase de entidad real (Employment) 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. + + + + + + + + + + + + + He aquí un documento de mapeo posible: + + + + + + + + employer_id_seq + + + + + + + + + + employment_id_seq + + + + + + + + + + + + + + + + + + + + + employee_id_seq + + + + + + + + + + +]]> + + + Y he aquí el esquema de tablas generado por SchemaExport. + + + + + + + + Autor/Obra + + + Considera el siguiente modelo de las relaciones entre Work, + Author y Person. Representamos la relación entre Work + y Author como una asociación muchos-a-muchos. Elegimos representar la relación entre + Author y Person como una asociación uno-a-uno. Otra posibilidad + hubiese sido que Author extendiera Person. + + + + + + + + + + + + + El siguiente documento de mapeo representa estas relaciones correctamente: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]]> + + + Hay cuatro tablas en este mapeo. works, authors y persons + tienen los datos de obra, autor y persona respectivamente. author_work es una tabla de + asociación enlazando autores a obras. He aquí el esquema de tablas, tal como fue generado por + SchemaExport. + + + + + + + + Cliente/Orden/Producto + + + Ahora considera un modelo de las relaciones entre Customer, + Order y LineItem y Product. + Hay una asociación uno-a-muchos entre Customer y Order, + pero, ¿cómo deberíamos representar Order / LineItem / Product? + He elegido mapear LineItem como una clase de asociación representando la + asociación muchos-a-muchos entre Order y Product. En Hibernate, + esto se llama un elemento compuesto. + + + + + + + + + + + + + El documento de mapeo: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]]> + + + customers, orders, line_items y + products tienen los datos de cliente, orden, ítem de línea de orden y producto + respectivamente. Además line_items actúa como una tabla de asociación enlazando + órdenes con productos. + + + + + + + + Mapeos misceláneos de ejemplo + + + 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 + test de la distribución de Hibernate. + + + POR HACER: poner palabras alrededor de este material + + + Asociación uno-a-uno "Tipificada" + + + + name + 'HOME' + + + name + 'MAILING' + + + + + + + + + + + +]]> + + + + Ejemplo de clave compuesta + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ( select sum(li.quantity*p.price) + from LineItem li, Product p + where li.productId = p.productId + and li.customerId = customerId + and li.orderNumber = orderNumber ) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ( select sum(li.quantity) + from LineItem li + where li.productId = productId ) + + + +]]> + + + + Muchos-a-muchos con atributo de clave compuesta compartido + + + + + + + + + + + + + org + + + + + + + + + + + + + + + + + + org + + + +]]> + + + + Discriminación basada en contenido + + + + + + + + + + case + when title is not null then 'E' + when salesperson is not null then 'C' + else 'P' + end + + + + + + + + + + + + + + + + + + + + + + + + +]]> + + + + Asociaciones sobre claves alternativas + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]]> + + + + + + diff --git a/documentation/manual/es-ES/src/main/docbook/content/example_parentchild.xml b/documentation/manual/es-ES/src/main/docbook/content/example_parentchild.xml new file mode 100644 index 0000000000..c8ca224347 --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/content/example_parentchild.xml @@ -0,0 +1,362 @@ + + Ejemplo: Padre/Hijo + + + 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 Parent como Child + como clases de entidad con una asociación <one-to-many> desde Parent + a Child. (El enfoque alternativo es declarar el Child como un + <composite-element>.) 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 asociación uno a muchos bidireccional + con tratamiento en cascada para modelar una relación padre / hijo eficiente y elegantemente. + ¡No es para nada difícil! + + + + Una nota sobre las colecciones + + + 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: + + + + + + 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. + + + + + 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. + + + + + 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. + + + + + + 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. + + + + + + Uno-a-muchos bidirectional + + + Supón que empezamos con una asociación simple <one-to-many> desde + Parent a Child. + + + + + +]]> + + + Si ejecutásemos el siguiente código + + + + + + Hibernate publicaría dos sentencias SQL: + + + + + un INSERT para crear el registro de c + + + + un UPDATE para crear el enlace desde p a + c + + + + + + Esto no es sólo ineficiente, sino que además viola cualquier restricción NOT NULL en la + columna parent_id. Podemos reparar la violación de restricción de nulabilidad + especificando not-null="true" en el mapeo de la colección: + + + + + +]]> + + + Sin embargo, esta no es la solución recomendada. + + + El caso subyacente de este comportamiento es que el enlace (la clave foránea parent_id) + de p a c no es considerado parte del estado del objeto + Child y por lo tanto no es creada en el INSERT. De modo que la + solución es hacer el enlace parte del mapeo del Child. + + + ]]> + + + (Necesitamos además añadir la propiedad parent a la clase Child.) + + + + Ahora que la entidad Child está gestionando el estado del enlace, le decimos a la + colección que no actualice el enlace. Usamos el atributo inverse. + + + + + +]]> + + + El siguiente código podría ser usado para añadir un nuevo Child + + + + + + Y ahora, ¡Sólo se publicaría un INSERT de SQL! + + + + Para ajustar un poco más las cosas, podríamos crear un método addChild() en + Parent. + + + + + + Ahora, el código para añadir un Child se ve así + + + + + + + + Ciclo de vida en cascada + + + La llamada explícita a save() es aún molesta. Apuntaremos a esto usando tratamientos + en cascada. + + + + + +]]> + + + Esto simplifica el código anterior a + + + + + + Similarmente, no necesitamos iterar los hijos al salvar o borrar un Parent. + Lo siguiente quita p y todos sus hijos de la base de datos. + + + + + + Sin embargo, este código + + + + + + no quitará c de la base de datos; sólo quitará el enlace a p + (y causará una violación a una restricción NOT NULL). Necesitas borrar el hijo + explícitamente llamando a delete(). + + + + + + Ahora, en nuestro caso, un Child no puede existir realmente sin su padre. De modo que + si quitamos un Child de la colección, realmente queremos que sea borrado. Para esto, + debemos usar cascade="all-delete-orphan". + + + + + +]]> + + + Nota: aunque el mapeo de la colección especifique inverse="true", 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 setParent(). + + + + + + Tratamiento en cascada y <literal>unsaved-value</literal> + + + Supón que hemos cargado un Parent en una Session, hemos hecho algunos + cambios en una acción de UI y deseamos hacer persistentes estos cambios en una nueva sesión llamando a + update(). El Parent 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 Parent como + Child tienen propiedades identificadoras generadas de tipo Long. + Hibernate usará el identificador y el valor de la propiedad de versión/timestamp para determinar cuáles de + los hijos son nuevos. (Ver .) En Hibernate3, no es + más necesario especificar un unsaved-value explícitamente. + + + + The following code will update parent and child and insert + newChild. + + + + + + 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. + + + + + + + Conclusión + + + 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. + + + + Hemos mencionado una alternativa en el primer párrafo. Ninguno de los temas anteriores existe en el caso + de los mapeos <composite-element>, 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. + + + + + \ No newline at end of file diff --git a/documentation/manual/es-ES/src/main/docbook/content/example_weblog.xml b/documentation/manual/es-ES/src/main/docbook/content/example_weblog.xml new file mode 100644 index 0000000000..83e2c108c9 --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/content/example_weblog.xml @@ -0,0 +1,429 @@ + + Ejemplo: Aplicación de Weblog + + + Clases Persistentes + + + 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). + + + + + + + + + + Mapeos de Hibernate + + + Los mapeos XML ahora deben ser absolutamente directos. + + + + + + + + + + + + + + + + + + + + + + + + + + +]]> + + + + + + + + + + + + + + + + + + + + + + + + +]]> + + + + + Código Hibernate + + + La siguiente clase demuestra algunos de los tipos de cosas que podemos haces con estas clases, + usando Hibernate. + + + :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; + } +}]]> + + + + + diff --git a/documentation/manual/es-ES/src/main/docbook/content/filters.xml b/documentation/manual/es-ES/src/main/docbook/content/filters.xml new file mode 100644 index 0000000000..8675dbdacc --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/content/filters.xml @@ -0,0 +1,130 @@ + + Filtrando datos + + + Hibernate3 provee un nuevo enfoque innovador para manejar datos con reglas de "visibilidad". + Un filtro de Hibernate es un filtro global, con nombre y parametrizado + que puede ser habilitado o deshabilitado para una sesión de Hibernate en particular. + + + + Filtros de Hibernate + + + 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 usar los filtros, éstos deben primero ser definidos y luego unidos a los elementos de mapeo + apropiados. Para definir un filtro, usa el elemento <filter-def/> dentro + de un elemento <hibernate-mapping/>: + + + + +]]> + + + Entonces este filtro puede ser unido a una clase: + + + + ... + +]]> + + + o a una colección: + + + + +]]> + + + o incluso a ambos (o muchos de cada uno) al mismo tiempo. + + + + Los métodos en Session son: enableFilter(String filterName), + getEnabledFilter(String filterName), y disableFilter(String filterName). + Por defecto, los filtros no están habilitados para una sesión dada; deben ser + habilitados explícitamente por medio del uso del método Session.enableFilter(), + que devuelve una instancia de la interface Filter. Usando el filtro simple definido + arriba, esto se vería así: + + + + + + Nota que los métodos en la interface org.hibernate.Filter permiten el encadenamiento de métodos + común en gran parte de Hibernate. + + + + Un ejemplo completo, usando datos temporales con un patrón efectivo de fechas de registro: + + + + + + + +... + + + +... + + + + + +... + + + + + +]]> + + + 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: + + + :targetSalary") + .setLong("targetSalary", new Long(1000000)) + .list(); +]]> + + + 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. + + + + 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. + + + + + + diff --git a/documentation/manual/es-ES/src/main/docbook/content/inheritance_mapping.xml b/documentation/manual/es-ES/src/main/docbook/content/inheritance_mapping.xml new file mode 100644 index 0000000000..2d4140af9c --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/content/inheritance_mapping.xml @@ -0,0 +1,464 @@ + + Mapeo de Herencia + + + Las Tres Estrategias + + + Hibernate soporta las tres estrategias básicas de mapeo de herencia: + + + + + + tabla por jerarquía de clases + + + + + tabla por subclase + + + + + tabla por clase concreta + + + + + + En adición, Hibernate soporta un cuarto, ligeramente diferente tipo + de polimorfismo: + + + + + + polimorfismo implícito + + + + + + 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 <subclass>, + y <joined-subclass> + y <union-subclass> bajo el mismo elemento + <class> raíz. Es posible mezclar juntas las + estrategias de tabla por jerarquía y tabla por subclase, bajo el mismo + elemento <class>, combinando los elementos + <subclass> y <join> + (ver debajo). + + + + Tabla por jerarquía de clases + + + Supón que tenemos una interface Payment, con + los implementadores CreditCardPayment, + CashPayment, ChequePayment. + El mapeo de tabla por jerarquía se vería así: + + + + + + + + + ... + + + ... + + + ... + + + ... + +]]> + + + Se requiere exactamente una tabla. Hay una gran limitación de esta estrategia de mapeo: + las columnas declaradas por las subclases, como CCTYPE, no pueden + tener restricciones NOT NULL. + + + + + + Tabla por subclase + + + Un mapeo de tabla por sublclase se vería así: + + + + + + + + ... + + + + ... + + + + ... + + + + ... + +]]> + + + 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). + + + + + + Tabla por subclase, usando un discriminador + + + 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 <subclass> + y <join>, como sigue: + + + + + + + + + ... + + + + + ... + + + + + + ... + + + + + + ... + + +]]> + + + la declaración opcional fetch="select" dice a Hibernate + que no recupere los datos de la subclase ChequePayment + usando una unión externa (outer join) al consultar la superclase. + + + + + + Mezclando tabla por jerarquía de clases con tabla por subclase + + + Puedes incluso mezclar las estrategias de tabla po jerarquía y tabla por + subclase usando este enfoque: + + + + + + + + + ... + + + + ... + + + + ... + + + ... + +]]> + + + Para cualquiera de estas estrategias de mapeo, una asociación polimórfica + a la clase raíz Payment es mapeada usando <many-to-one>. + + + ]]> + + + + + Tabla por clase concreta + + + Podríamos ir de dos maneras a la estrategia de mapeo de tabla por clase + concreta. La primera es usar <union-subclass>. + + + + + + + + ... + + + ... + + + ... + + + ... + +]]> + + + Están implicadas tres tablas. Cada tabla define columnas para todas las + propiedades de la clase, inccluyendo las propiedades heredadas. + + + + 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. + + + + + + Tabla por clase concreta, usando polimorfismo implícito + + + Un enfoque alternativo es hacer uso de polimorfismo implícito: + + + + + + + + ... + + + + + + + + ... + + + + + + + + ... +]]> + + + Nota que en ningún sitio mencionamos la interface Payment + explícitamente. Nota además que las propiedades de Payment + son mapeadas en cada una de las subclases. Si quieres evitar duplicación, + considera usar entidades XML. (por ejemplo, + [ <!ENTITY allproperties SYSTEM "allproperties.xml"> ] + en la declaración DOCTYPE y &allproperties; + en el mapeo). + + + + La desventaja de este enfoque es que Hibernate no genera UNIONs + de SQL al realizar consultas polimórficas. + + + + Para esta estrategia de mapeo, una asociación polimórfica a Payment + es mapeada generalmente usando <any>. + + + + + + + + +]]> + + + + + Mezclando polimorfismo implícito con otros mapeos de herencia + + + Hay una cosa más por notar acerca de este mapeo. Ya que las subclases se mapean + cada una en su propio elemento <class> (y ya que + Payment 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 Payment.) + + + + + + + + + ... + + + + + + + + + ... + + + + ... + + + + + ... + +]]> + + + Una vez más, no mencionamos a Payment explícitamente. + Si ejecutamos una consulta contra la interface Payment + - por ejemplo, from Payment - Hibernate devuelve + automáticamente instancias de CreditCardPayment + (y sus subclases, ya que ellas también implementan Payment), + CashPayment y ChequePayment pero + no instancias de NonelectronicTransaction. + + + + + + + + Limitaciones + + + 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 <union-subclass>. + + + + La siguiente tabla muestra las limitaciones de mapeos de tabla por + clase concreta, y de polmorfismo implícito, en Hibernate. + + + + Funcionalidades de mapeo de herencia + + + + + + + + + + + + Estrategia de herencia + muchos-a-uno polimórfica + uno-a-uno polimórfica + uno-a-muchos polimórfica + mushos-a-muchos polimórfica + load()/get() polimórficos + Consultas polimórficas + Uniones polimórficas + Recuperación por unión externa (outer join) + + + + + tabla por jerarquía de clases + <many-to-one> + <one-to-one> + <one-to-many> + <many-to-many> + s.get(Payment.class, id) + from Payment p + from Order o join o.payment p + soportada + + + tabla por subclase + <many-to-one> + <one-to-one> + <one-to-many> + <many-to-many> + s.get(Payment.class, id) + from Payment p + from Order o join o.payment p + soportada + + + tabla por clase concreta (union-subclass) + <many-to-one> + <one-to-one> + <one-to-many> (para inverse="true" solamente) + <many-to-many> + s.get(Payment.class, id) + from Payment p + from Order o join o.payment p + soportada + + + tabla por clase concreta (polimorfismo implícito) + <any> + no soportada + no soportada + <many-to-any> + s.createCriteria(Payment.class).add( Restrictions.idEq(id) ).uniqueResult() + from Payment p + no suportadas + no soportada + + + +
+ +
+ +
diff --git a/documentation/manual/es-ES/src/main/docbook/content/performance.xml b/documentation/manual/es-ES/src/main/docbook/content/performance.xml new file mode 100644 index 0000000000..7249f99d27 --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/content/performance.xml @@ -0,0 +1,1334 @@ + + Mejorando el rendimiento + + + Estrategias de recuperación + + + Una estrategia de recuperación 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 + Criteria en particular. + + + + Hibernate3 define las siguientes estrategias de recuperación: + + + + + + Recuperación por unión (join fetching) - Hibernate recupera la + instancia asociada o colección en la misma SELECT, usando una + OUTER JOIN. + + + + + Recuperación por selección (select fetching) - se usa una segunda + SELECT para recuperar la entidad asociada o colección. A menos que + deshabilites explícitamente la recuperación perezosa especificando lazy="false", + la segunda selección sólo será ejecutada cuando realmente accedas a la asociación. + + + + + Recuperación por subselección (subselect fetching) - se usa una segunda + SELECT 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 lazy="false", esta segunda selección sólo + será ejecutada cuando realmente accedas a la asociación. + + + + + Recuperación en lote - 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 + SELECT, especificando una lista de claves primarias o de claves foráneas. + + + + + + Hibernate también distingue entre: + + + + + + Recuperación inmediata - una asociación, colección o atributo es recuperado + inmediatamente, cuando el dueño es cargado. + + + + + Recuperación perezosa de colecciones - se recupera una colección cuando la + aplicación invoca una operación sobre la colección. (Esto es por defecto para las colecciones.) + + + + + Recuperación por proxy - se recupera una asociación monovaluada cuando se + invoca un método que no sea el getter del identificador sobre el objeto asociado. + + + + + Recuperación perezosa de atributos - 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. + + + + + + Aquí tenemos dos nociones ortogonales: cuándo se recupera la aplicación, + y cómo es recuperada (qué SQL es usado). ¡No las confundas! Usamos + fetch para afinar el rendimiento. Podemos usar lazy para + definir un contrato sobre qué datos están siempre disponibles en cualquier instancia separada de + una clase en particular. + + + + Trabajando con asociaciones perezosas + + + 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. + + + + Nota: si estableces hibernate.default_batch_fetch_size, 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). + + + + 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: + + + + + + Ya que la colección de permisos no fue inicializada cuando se cerró la Session, + la colección no será capaz de cargar su estado. Hibernate no soporta la inicialización + perezosa de objetos separados. La solución es mover el código que lee de la colección + a justo antes que la transacción sea comprometida. + + + + Alternativamente, podríamos usar una colección no perezosa o asociación, especificando + lazy="false" 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! + + + + 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. + + + + + + Afinando las estrategias de recuperación + + + 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: + + + + + + + + ]]> + + + La estrategia de recuperación definida en el documento de mapeo afecta a: + + + + + + las recuperaciones vía get() o load() + + + + + las recuperaciones que ocurren implícitamente cuando se navega una asociación + (recuperación perezosa) + + + + + las consultas de Criteria + + + + + + 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 + left join fetch 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 + Criteria, usarías setFetchMode(FetchMode.JOIN). + + + + Si acaso lo deseases, podrías cambiar la estrategia de recuperación usada por + get() or load(); simplemente usa una consulta + Criteria, por ejemplo: + + + + + + (Esto es el equivalente de Hibernate de lo que otras soluciones ORM llaman un "plan de recuperación".) + + + + Una forma completamente diferente de evitar problemas con selecciones N+1 es usar el caché de + segundo nivel. + + + + + + Proxies de asociaciones de un solo extremo + + + 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). + + + + Por defecto, Hibernate3 genera proxies (en el arranque) para todas las clases persistentes y los usa + para habilitar la recuperación perezosa de asociaciones muchos-a-uno y + uno-a-uno. + + + + El fichero de mapeo puede declarar una interface a usar como interface de proxy para esa clase, + con el atributo proxy. Por defecto, Hibernate usa una subclase de la clase. + 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! + + + + Hay algunos puntos a tener en cuenta al extender este enfoque a clases polimórficas, por ejemplo. + + + + ...... + + ..... + +]]> + + + Primero, las instancias de Cat nunca serán objeto de un cast a + DomesticCat, incluso aunque la instancia subyacente sea instancia de + DomesticCat: + + + + + + Segundo, es posible romper con el operador == de un proxy. + + + + + + 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: + + + + + + Tercero, no debes usar un proxy CGLIB para una clase final o una clase + con algún método final. + + + + 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. + + + + 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: + + + + ...... + + ..... + +]]> + + + donde CatImpl implementa la interface Cat y + DomesticCatImpl implementa la interface DomesticCat. + Entonces load() o iterate() pueden devolver instancias de + Cat y DomesticCat. (Nota que list() + usualmente no devuelve proxies.) + + + + + + Las relaciones también son inicializadas perezosamente. Esto significa que debes declarar + cualquier propiedad como de tipo Cat, no CatImpl. + + + + Ciertas operaciones no requieren inicialización de proxies. + + + + + + equals(), si la clase persistente no sobrescribe equals() + + + + + hashCode(), si la clase persistente no sobrescribe + hashCode() + + + + + El método getter del identificador + + + + + + Hibernate detectará las clase persistentes que sobrescriban equals() o + hashCode(). + + + + + + Inicializando colecciones y proxies + + + Una LazyInitializationException será lanzada por Hibernate si una colección + o proxy sin inicializar es accedido fuera del ámbito de la Session, es decir, + cuando la entidad que posee la colección o que tiene la referencia al proxy esté en el estado + separada. + + + + A veces necesitamos asegurarnos que un proxy o colección esté inicializado antes de cerrar la + Session. Por supuesto, siempre podemos forzar la inicialización llamando a + cat.getSex() o cat.getKittens().size(), por ejemplo. + Pero esto es confuso a lectores del código y no es conveniente para código genérico. + + + + Los métodos estáticos Hibernate.initialize() y + Hibernate.isInitialized() proveen a la aplicación de una forma conveniente de + trabajar con colecciones o proxies inicializados perezosamente. + Hibernate.initialize(cat) forzará la inicialización de un proxy, + cat, en tanto su Session esté todavía abierta. + Hibernate.initialize( cat.getKittens() ) tiene un efecto similar para la colección + de gatitos. + + + + Otra opción es mantener la Session 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 Session esté abierta cuando se inicializa una colección. Existen dos formas + básicas de tratar este tema: + + + + + + En una aplicación basada web, puede usarse un filtro de servlets para cerrar la + Session sólo bien al final de una petición de usuario, una + vez que el rendering de la vista esté completa (el patrón Sesión Abierta en + Vista (Open Session in View)). 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 Session 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 Session. Recomendamos que se use una variable + ThreadLocal para tener la Session actual (ver + el capítulo 1, , para una implementación de ejemplo). + + + + + 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 Hibernate.initialize() + 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 FETCH o una FetchMode.JOIN en + Criteria. Esto es usualmente más fácil si adoptas el patrón + Comando en vez de un Fachada de Sesión. + + + + + Puedes también adjuntar un objeto cargado previamente a una nueva Session + con merge() o lock() antes de acceder a colecciones + no inicializadas (u otros proxies). ¡No, Hibernate no, y ciertamente no + debe hacer esto automáticamente, ya que introduciría semánticas de transacción ad hoc! + + + + + + 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. + + + + Puedes usar un filtro de colecciones para obtener el tamaño de una colección sin inicializarla: + + + + + + El método createFilter() se usa también para recuperar eficientemente subconjuntos + de una colección sin necesidad de inicializar toda la colección: + + + + + + + + Usando recuperación en lotes + + + 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. + + + + 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 Cat cargadas en una + Session, cada Cat tiene una referencia a su owner, + una Person. La clase Person está mapeada con un proxy, + lazy="true". Si ahora iteras a través de todos los gatos y llamas a + getOwner() para cada uno, Hibernate por defecto ejecutará 25 sentencias + SELECT para traer los dueños tratados con proxies. Puedes afinar este comportamiento + especificando un batch-size en el mapeo de Person: + + + ...]]> + + + Hibernate ahora ejecutará sólo tres consultas, el patrón es 10, 10, 5. + + + + También puedes habilitar la recuperación en lotes para colecciones. Por ejemplo, si cada + Person tiene una colección perezosa de Cats, y hay 10 + personas actualmente cargadas en la Session, iterar a través de las 10 personas + generará 10 SELECTs, una para cada llamada a getCats(). + Si habilitas la recuperación en lotes para la colección de cats en el mapeo de + Person, Hibernate puede recuperar por adelantado las colecciones: + + + + + ... + +]]> + + + Con un batch-size de 3, Hibernate cargará 3, 3, 3, 1 colecciones en cuatro + SELECTs. Una vez más, el valor del atributo depende del número esperado de + colecciones sin inicializar en una Session en particular. + + + + 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 conjunto + anidado o una ruta materializada podría ser una mejor opción + para árboles que sean de lectura en la mayoría de los casos.) + + + + + + Usando recuperación por subselección + + + 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. + + + + + + + + Usando recuperación perezosa de propiedades + + + Hibernate3 soporta la recuperación perezosa de propiedades individuales. Esta técnica de optimización + es también conocida como grupos de recuperación (fetch groups). 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 habilitar la carga perezosa de propiedades, establece el atributo lazy en tus + mapeos de propiedades: + + + + + + + + + +]]> + + + ¡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 la instrumentación del bytecode, usa la siguiente tarea Ant: + + + + + + + + + + + + + + +]]> + + + 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. + + + + Puedes forzar la usual recuperación temprana de propiedades usando fetch all properties + en HQL. + + + + + + + + El Caché de Segundo Nivel + + + Una Session 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 SessionFactory) + 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é). + + + + 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 org.hibernate.cache.CacheProvider usando la propiedad + hibernate.cache.provider_class. + + + + Proveedores de Caché + + + + + + + + + Caché + clase del Provedor + Tipo + Cluster Seguro + Caché de Consultas Soportado + + + + + Hashtable (no pensado para uso en producción) + org.hibernate.cache.HashtableCacheProvider + memoria + + + + + EHCache + org.hibernate.cache.EhCacheProvider + memoria, disco + + + + + OSCache + org.hibernate.cache.OSCacheProvider + memoria, disco + + + + + SwarmCache + org.hibernate.cache.SwarmCacheProvider + clusterizado (ip multicast) + sí (invalidación en cluster) + + + + TreeCache de JBoss + org.hibernate.cache.TreeCacheProvider + clusterizado (ip multicast), transaccional + sí (replicación) + sí (requiere sincronización de reloj) + + + +
+ + + Mapeos de caché + + + El elemento <cache> de una mapeo de clase o colección tiene la siguiente + forma: + + + + + + + ]]> + + + + usage especifica la estrategia de caching: + transactional, + read-write, + nonstrict-read-write o + read-only + + + + + + + Alternativamente (¿preferiblemente?), puedes especificar los elementos + <class-cache> y <collection-cache> en + hibernate.cfg.xml. + + + + El atributo usage especifica una estrategia de concurrencia al + caché. + + + + + + Estrategia: sólo lectura (read only) + + + Si tu aplicación necesita leer pero nunca modificar las instancias de una clase persistente, + puede usarse un caché read-only. Esta es la mejor y más simple estrategia. + Es incluso perfectamente segura de usar en un cluster. + + + + + .... +]]> + + + + + + Estrategia: lectura/escritura (read/write) + + + Si la aplicación necesita actualizar datos, un caché read-write 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 + hibernate.transaction.manager_lookup_class, mencionando una estrategia para obtener + el TransactionManager de JTA. En otros entornos, debes asegurarte que la transacción + esté completada cuando se llame a Session.close() o + Session.disconnect(). 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 no no lo soportan. + + + + + .... + + + .... + +]]> + + + + + Estrategia: lectura/escritura no estricta (nonstrict read/write) + + + 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é nonstrict-read-write podría ser + apropiado. Si se usa el caché en un entorno JTA, debes especificar + hibernate.transaction.manager_lookup_class. En otros entornos, debes asegurarte que la + transacción se haya completado cuando se llame a Session.close() o + Session.disconnect(). + + + + + + Estrategia: transaccional + + + La estrategia de caché transactional 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 hibernate.transaction.manager_lookup_class. + + + + + + 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. + + + + Soporte a Estrategia de Concurrencia a Caché + + + + + + + + + Caché + read-only + nonstrict-read-write + read-write + transactional + + + + + Hashtable (no pensado para uso en producción) + + + + + + + EHCache + + + + + + + OSCache + + + + + + + SwarmCache + + + + + + + JBoss TreeCache + + + + + + + +
+ +
+ + + Gestionando los cachés + + + Siempre que pases un objeto a save(), update() + o saveOrUpdate() y siempre que recuperes un objeto usando + load(), get(), list(), + iterate() o scroll(), ese objeto es agregado + al caché interno de la Session. + + + Cuando subsecuentemente se llame a flush(), 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 evict() para quitar el objeto y sus colecciones + del caché de primer nivel. + + + + + + La Session también provee un método contains() para determinar + si una instancia pertenece al caché de la sesión. + + + + Para desahuciar (evict) todos los objetos del caché de sesión, llama a Session.clear(). + + + + Para el caché de segundo nivel, hay métodos definidos en SessionFactory para + desahuciar el estado en caché de una instancia, clase entera, instancia de colección o rol + enter de colección. + + + + + + El CacheMode controla cómo una sesión en particular interactúa con el caché de segundo + nivel. + + + + + + CacheMode.NORMAL - lee ítems desde y escribe ítems hacia el caché de segundo nivel + + + + + CacheMode.GET - lee ítems del caché de segundo nivel, pero no escribe al caché de + segundo nivel excepto al actualizar datos + + + + + CacheMode.PUT - escribe ítems al caché de segundo nivel, pero no lee del caché de segundo + nivel + + + + + CacheMode.REFRESH - escribe ítems al caché de segundo nivel, pero no lee del caché de + segundo nivel, saltándose el efecto de hibernate.cache.use_minimal_puts, forzando + un refresco del caché de segundo nivel para todos los ítems leídos de la base de datos + + + + + + Para navegar por los contenidos de una región de caché de segundo nivel o de consultas, usa la API de + Statistics: + + + + + + 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: + + + + + + + + El Caché de Consultas + + + 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: + + + + + + Esta configuración causa la creación de dos nuevas regiones de caché - una teniendo en caché + conjuntos resultado de consulta (org.hibernate.cache.StandardQueryCache), + el otro teniendo timestamps de las actualizaciones más recientes a tablas consultables + (org.hibernate.cache.UpdateTimestampsCache). 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. + + + + 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 + Query.setCacheable(true). Esta llamada permite a la consulta buscar + resultados existentes en caché o agregar sus resultados al caché cuando se ejecuta. + + + + 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 Query.setCacheRegion(). + + + + + + Si la consulta debe forzar un refresco de si región del caché de consultas, debes llamar a + Query.setCacheMode(CacheMode.REFRESH). 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 SessionFactory.evictQueries(). + + + + + + Entendiendo el rendimiento de Colecciones + + + 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. + + + + Taxonomia + + Hibernate define tres tipos básicos de colecciones: + + + + colecciones de valores + + + asociaciones uno a muchos + + + asociaciones muchos a muchos + + + + + 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: + + + + + colecciones indexadas + + + conjuntos (sets) + + + bolsas (bags) + + + + + Todas las colecciones indexadas (mapas, listas, arrays) tienen una clave primaria + consistente de las columnas <key> y <index>. + 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. + + + + Los conjuntos (sets) tienen una clave primaria consistente en <key> + 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 + SchemaExport realmente cree la clave primaria de un <set> + por ti, debes declarar todas las columnas como not-null="true".) + + + + Los mapeos de <idbag> definen una clave delegada, de modo que siempre + resulten eficientes de actualizar. De hecho, son el mejor caso. + + + + 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 DELETE) y recreando la colección siempre que cambia. + Esto podría ser muy ineficiente. + + + + 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.) + + + + + + Las listas, mapas, idbags y conjuntos son las colecciones más eficientes de actualizar + + + 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. + + + + 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 Set, Hibernate ni siquiera actualiza una fila con + UPDATE cuando se "cambia" un elemento. Los cambios a un Set + siempre funcionan por medio de INSERT y DELETE + (de filas individuales). Una vez más, esta consideración no se aplica a las asociaciones + uno a muchos. + + + + 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. + + + + 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 inverse="true". + 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. + + + + + + Los Bags y las listas son las colecciones inversas más eficientes + + + 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 + inverse="true" (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 Collection.add() o + Collection.addAll() siempre deben devolver true para un bag o List + (no como un Set). Esto puede hacer el siguiente código común mucho más rápido. + + + + + + + + Borrado de un solo tiro + + + 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 list.clear(), por ejemplo). En este caso, Hibernate + publicará una sola DELETE, ¡y listo! + + + + 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 INSERT y dos sentencias DELETE + (a menos que la colección sea un bag). Esto es ciertamente deseable. + + + + Sin embargo, supón que quitamos dieciocho elementos, dejando dos y luego añadimos tres nuevos elementos. + Hay dos formas posibles de proceder + + + + + borrar dieciocho filas una a una y luego insertar tres filas + + + quitar toda la colección (en un solo DELETE de SQL) e insertar todos los + cinco elementos actuales (uno a uno) + + + + + 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.) + + + + 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. + + + + Por supuesto, el borrado-de-un-solo-tiro no se aplica a colecciones mapeadas + inverse="true". + + + + + + + + Monitoreando el rendimiento + + + 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 SessionFactory. + + + + Monitoreando una SessionFactory + + + Puedes acceder a las métricas de SessionFactory de dos formas. + Tu primera opción es llamar a sessionFactory.getStatistics() y + leer o mostrar por pantalla la Statistics por ti mismo. + + + + Hibernate puede también usar JMX para publicar las métricas si habilitas el MBean + StatisticsService. Puede habilitar un solo MBean para todas tus + SessionFactory o una por fábrica. Mira el siguiente código para + ejemplos de configuración minimalistas: + + + + + + + + + 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 hibernateStatsBean.setSessionFactoryJNDIName("my/JNDI/Name") + + + Puedes (des)activar el monitoreo de una SessionFactory + + + + + en tiempo de configuración, establece hibernate.generate_statistics a + false + + + + + + + en tiempo de ejecución: sf.getStatistics().setStatisticsEnabled(true) + o hibernateStatsBean.setStatisticsEnabled(true) + + + + + + Las estadísticas pueden ser reajustadas programáticamente usando el método clear(). + Puede enviarse un resumen a un logger (nivel info) usando el método logSummary(). + + + + + + Métricas + + + 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 Statistics, en tres categorías: + + + + + Métricas relacionadas al uso general de Session usage, tales como + número de sesiones abiertas, conexiones JDBC recuperadas, etc, + + + + + Métricas relacionadas a las entidades, colecciones, consultas, y cachés como un todo. + (también conocidas como métricas globales). + + + + + Métricas detalladas relacionadas a una entidad, colección, consulta o región de caché + en particular. + + + + + + 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. + + + + 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 Statistics, + EntityStatistics, CollectionStatistics, + SecondLevelCacheStatistics, y QueryStatistics para más información. + El siguiente código muestra un ejemplo sencillo: + + + + + + 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: + getQueries(), getEntityNames(), + getCollectionRoleNames(), y getSecondLevelCacheRegionNames(). + + + + + + +
\ No newline at end of file diff --git a/documentation/manual/es-ES/src/main/docbook/content/persistent_classes.xml b/documentation/manual/es-ES/src/main/docbook/content/persistent_classes.xml new file mode 100644 index 0000000000..980bf1af0a --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/content/persistent_classes.xml @@ -0,0 +1,478 @@ + + Clases Persistentes + + + 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. + + + + 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 Map, + por ejemplo. + + + + Un ejemplo simple de POJO + + + La mayoría de aplicaciones Java requieren una clase + representando felinos. + + + + + + Aquí hay cuatro reglas principales a seguir: + + + + Implementa un constructor sin argumentos + + + Cat 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 Constructor.newInstance(). Recomendamos fuertemente tener + un constructor por defecto con al menos visibilidad de package para la + generación de proxies en tiempo de ejecución en Hibernate. + + + + + Provee una propiedad identificadora (opcional) + + + Cat tiene una propiedad llamada id. 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, java.lang.String + o java.util.Date. (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.) + + + + 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. + + + + De hecho, alguna funcionalidad está disponible sólo para clases que + declaran una propiedad identificadora: + + + + + + Reasociación transitiva de objetos separados (actualizaciones o + fusiones en cascada) - ver + + + + + Session.saveOrUpdate() + + + + + Session.merge() + + + + + + Recomendamos que declares propiedades identificadoras nombradas-consistentemente + en clases persistentes. Mas aún, recomendamos que uses un tipo nulable + (es decir, no primitivo). + + + + + Prefiere las clases no finales (opcional) + + Un aspecto central de Hibernate, proxies, 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. + + + Puedes persistir con Hibernate clases final 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. + + + Debes también evitar declarar métodos public final + en clases non-final. Si quieres usar una clase con un método public + final, debes deshabilitar explícitamente el uso de proxies estableciendo + lazy="false". + + + + + Declara métodos de acceso y modificación para los campos persistentes (opcional) + + Cat 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 getFoo, isFoo y setFoo. + Puedes cambiar a acceso directo a campos para propiedades en particular, de ser necesario. + + + + Las propiedades no necesitan ser declaradas públicas. Hibernate puede + persistir una propiedad con un par get / set protected o private. + + + + + + Implementando herencia + + + Una subclase puede a su vez observar la primera y segunda regla. Hereda su + propiedad identificadora de la superclase, Cat. + + + + + + + Implementando <literal>equals()</literal> y <literal>hashCode()</literal> + + + + Tienes que sobrescribir los métodos equals() y hashCode() + si : + + + + + piensas poner instancias de clases persistentes en un Set + (la forma recomendada de representar asociaciones multivaluadas) + y + + + + + piensas usar reasociación de instancias separadas. + + + + + + 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 equals() y hashCode() si + deseamos tener una semántica significativa de Sets. + + + + La forma más obvia es implementar equals()/hashCode() + 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 + Set, sólo tendremos un elemento en el Set). + 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 Set, salvarla asignará un + valor identificador al objeto. Si equals() and hashCode() + están basados en el valor identificador, el código hash podría cambiar, + rompiendo el contrato de Set. 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. + + + + Recomendamos implementar equals() y hashCode() + usando igualdad de clave de negocio (Business key equality). + Igualdad de clave de negocio significa que el método equals() + 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 + natural): + + + + + + Nota que una clave de negocio no tiene que ser tan sólida como + una clave primaria candidata de base de datos (ver + ). Las propiedades inmutables o + únicas son usualmente buenas candidatas para una clave de negocio. + + + + + + Modelos dinámicos + + + Ten en cuenta que las siguientes funcionalidades están + consideradas actualmente experimentales y pueden cambiar en el futuro + cercano. + + + + 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 Maps de + Maps 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. + + + + Por defecto, Hibernate funciona en modo POJO normal. Puedes establecer una + representación de entidad por defecto para una SessionFactory + en particular usando la opción de configuración + default_entity_mode + (ver ). + + + + Los siguientes ejemplos demuestran la representación usando + Maps. Primero, en el fichero de mapeo, + tiene que declararse un entity-name en vez de + (o como agregado a) un nombre de clase: + + + + + + + + + + + + + + + + + + + + + + + +]]> + + + 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. + + + + Después de establecer el modo de entidad por defecto a + dynamic-map para la SessionFactory, + podemos trabajar en tiempo de ejecución con Maps + de Maps: + + + + + + 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. + + + + Los modos de representación de entidad pueden ser establecidos + por Session: + + + + + + + Por favor, ten en cuenta que la llamada a getSession() + usando un EntityMode está en la API de + Session, no en la de SessionFactory. + De esta forma, la nueva Session comparte la conexión + JDBC, transacción y otra información de contexto. Esto significa + que no tienes que llamar a flush() ni a close() + en la Session secundaria, y tembién dejar el manejo + de la transacción y de la conexión a la unidad de trabajo primaria. + + + + Puede encontrarse más información sobre las capacidades de + representación XML en . + + + + + + PORHACER: Documentar el framework de extensiones del usuario en los paquetes + de propiedad y proxies. + + + + diff --git a/documentation/manual/es-ES/src/main/docbook/master.xml b/documentation/manual/es-ES/src/main/docbook/content/preface.xml similarity index 60% rename from documentation/manual/es-ES/src/main/docbook/master.xml rename to documentation/manual/es-ES/src/main/docbook/content/preface.xml index 1a9f20e0c5..88cb2447cc 100644 --- a/documentation/manual/es-ES/src/main/docbook/master.xml +++ b/documentation/manual/es-ES/src/main/docbook/content/preface.xml @@ -1,63 +1,10 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - -]> + - - - - HIBERNATE - Persistencia Relacional para Java Idiomático - Documentación de Referencia de Hibernate - 3.0.5 - - - + Prefacio - - 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. - - - - Traductor(es): Bernardo Antonio Buffa Colomé <kreimer@bbs.frc.utn.edu.ar> - - Trabajar con software orientado a objetos y una base de datos relacional puede ser @@ -108,8 +55,8 @@ Dale una mirada al directorio eg/ en la distribución de Hibernate, contiene una aplicación independiente simple. - Copia tu driver JDBC al directorio lib/ y edita - etc/hibernate.properties, especificando los valores + Copia tu driver JDBC al directorio lib/ y edita + etc/hibernate.properties, especificando los valores correctos para tu base de datos. Desde línea de comandos en el directorio de la distribución, tipea ant eg (usando Ant), o bajo Windows, tipea build eg. @@ -162,42 +109,4 @@ JBoss Professional. - - - &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; - - - + \ No newline at end of file diff --git a/documentation/manual/es-ES/src/main/docbook/content/query_criteria.xml b/documentation/manual/es-ES/src/main/docbook/content/query_criteria.xml new file mode 100644 index 0000000000..8bdbf5def3 --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/content/query_criteria.xml @@ -0,0 +1,431 @@ + + Consultas por Criterios + + + Acompaña a Hibernate una API de consultas por criterios intuitiva y extensible. + + + + Creando una instancia de <literal>Criteria</literal> + + + La interface org.hibernate.Criteria representa una consulta contra + una clase persistente en particular. La Session es una fábrica de instancias + de Criteria. + + + + + + + + Estrechando el conjunto resultado + + + Un criterio individual de consulta es una instancia de la interface + org.hibernate.criterion.Criterion. La clase + org.hibernate.criterion.Restrictions define métodos de fábrica para obtener ciertos tipos + prefabricados de Criterion. + + + + + + Las restricciones pueden ser agrupadas lógicamente. + + + + + + + + Hay un gran rango de tipos de criterio prefabricados (subclases de Restrictions), + pero uno que es especialmente útil te deja especificar SQL directamente. + + + + + + El sitio {alias} será remplazado por el alias de fila de la entidad consultada. + + + + Un enfoque alternativo para obtener un criterio es tomarlo de una instancia de + Property. Puedes crear una Property llamando a + Property.forName(). + + + + + + + + Ordenando los resultados + + + Puedes ordenar los resultados usando org.hibernate.criterion.Order. + + + + + + + + + + Asociaciones + + + Puedes especificar fácilmente restricciones sobre las entidades relacionadas al navegar asociaciones + usando createCriteria(). + + + + + + nota que el segundo createCriteria() devuelve una nueva instancia de + Criteria, que hace referencia a los elementos de la colección + kittens. + + + + La siguiente forma alternativa es útil en ciertas circunstancias. + + + + + + (createAlias() no crea una nueva instancia de + Criteria.) + + + + ¡Observa que las colecciones de gatitos tenidas por las instancias de Cat devueltas + por las dos consultas previas no están prefiltradas por los criterios! Si deseas + recuperar sólo los gatitos que emparejen los criterios, debes usar returnMaps(). + + + + + + + + Recuperación dinámica de asociaciones + + + Puedes especificar la semántica de recuperación de asociaciones en tiempo de ejecución usando + setFetchMode(). + + + + + + Esta consulta recuperará tanto mate como kittens por + unión exterior (outer join). Ver para más información. + + + + + + Consultas por ejemplos + + + La clase org.hibernate.criterion.Example te permite construir un criterio de consulta + a partir de una instancia dada. + + + + + + Las propiedades de versión, los identificadores y las asociaciones son ignorados. Por defecto, + las propiedades valuadas a nulo son excluídas. + + + + Puedes ajustar cómo se aplica el Example. + + + + + + Puedes incluso usar ejemplos para colocar criterios sobre objetos asociados. + + + + + + + + Proyecciones, agregación y agrupamiento + + La clase org.hibernate.criterion.Projections es una fábrica de instancias de + Projection. Aplicamos una proyección a una consulta llamando a + setProjection(). + + + + + + + + No es necesario ningún "group by" explícito en una consulta por criterios. + Ciertos tipos de proyecciones son definidos para ser proyecciones agrupadas, + que además aparecen en la cláusula SQL group by. + + + + 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: + + + + + + + + Los métodos alias() y as() simplemente envuelven una instancia + de proyección en otra instancia de Projection con alias. Como un atajo, puedes asignar + un alias cuando agregas la proyección a una lista de proyecciones: + + + + + + + + Puedes también usar Property.forName() para expresar proyecciones: + + + + + + + + + + Consultas y subconsultas separadas + + La clase DetachedCriteria te deja crear una consulta fuera del ámbito de una sesión, + y entonces ejecutarla luego usando alguna Session arbitraria. + + + + + + También una DetachedCriteria puede usarse para expresar una subconsulta. + Las instancias de Criterion implicando subconsultas pueden obtenerse vía Subqueries o + Property. + + + + + + + + Incluso son posibles las subconsultas correlacionadas: + + + + + + + + + + Consultas por identificador natural + + + 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. + + + + Primero, debes mapear la clave natural de tu entidad usando + <natural-id>, y habilitar el uso del caché de segundo nivel. + + + + + + + + + + + + +]]> + + + Nota que esta funcionalidad no está pensada para uso con entidades con claves naturales + mutable. + + + + Seguido, habilita el caché de consulta de Hibernate. + + + + Ahora, Restrictions.naturalId() nos permite hacer uso de el algoritmo de caché + más eficiente. + + + + + + + diff --git a/documentation/manual/es-ES/src/main/docbook/content/query_hql.xml b/documentation/manual/es-ES/src/main/docbook/content/query_hql.xml new file mode 100644 index 0000000000..bd6df664b4 --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/content/query_hql.xml @@ -0,0 +1,1107 @@ + + HQL: El Lenguaje de Consulta de Hibernate + + + 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. + + + + Sensibilidad a Mayúsculas + + + Las consultas son insensibles a mayúsculas, excepto para nombres de clases Java y propiedades. De modo que + SeLeCT es lo mismo que sELEct e igual a SELECT, + pero org.hibernate.eg.FOO no lo es a org.hibernate.eg.Foo y + foo.barSet no es igual a foo.BARSET. + + + + 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. + + + + + + La cláusula from + + + La consulta más simple posible de Hibernate es de la forma: + + + + + + que simplemente devuelve todas las instancias de la clase eg.Cat. + Usualmente no necesitamos cualificar el nombre de la clase, ya que auto-import + está por defecto. De modo que casi siempre escribimos solamente: + + + + + + La mayoría del tiempo, necesitarás asignar un alias, ya que querrás referirte al + Cat en otras partes de la consulta. + + + + + + Esta consulta asigna el alias cat a las instancias de Cat, + de modo que podríamos usar ese alias luego en la consulta. La palabra clave as + es opcional; también podríamos escribir: + + + + + + Pueden aparecer múltiples clases, resultando en un producto cartesiano o unión "cruzada" (cross join). + + + + + + + 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, domesticCat). + + + + + + Asociaciones y uniones (joins) + + + Podemos también asignar aliases a entidades asociadas, e incluso a elementos de una colección de valores, + usando una join. + + + + + + + + + + Los tipos de join soportados son prestados de ANSI SQL + + + + + + inner join + + + + + left outer join + + + + + right outer join + + + + + full join (no útil usualmente) + + + + + + Las construcciones inner join, left outer join y + right outer join pueden ser abreviadas. + + + + + + Puedes proveer condiciones de unión extra usando la palabra clave with de HQL. + + + 10.0]]> + + + 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 para más + información. + + + + + + Usualmente a un fetch join no se necesita asignársele un alias, porque los objetos asociados no deben + ser usados en la cláusula where (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: + + + + + + Nota que la construcción fetch no puede usarse en consultas llamadas usando + scroll() o iterate(). Ni debe usarse fetch + junto con setMaxResults() o setFirstResult(). Tampoco puede usarse + fetch junto a una condición with 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 + full join fetch y right join fetch no son significativos. + + + + 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 + fetch all properties. + + + + + + + + + La cláusula select + + + La cláusula select escoge qué objetos y propiedades devolver in el conjunto resultado + de la consulta. Considera: + + + + + + La consulta seleccionará mates de otros Cats. + Realmente, puedes expresar esta consulta en un forma más compacta como: + + + + + + Las consultas pueden devolver propiedades de cualquier tipo de valor incluyendo propiedades de + tipo componente: + + + + + + + + Las consultas pueden devolver múltiples objetos y/o propiedades como un array de tipo + Object[], + + + + + + o como una List, + + + + + + o como un objeto real Java de tipo seguro, + + + + + + asumiendo que la clase Family tiene un constructor apropiado. + + + + Puedes asignar aliases para seleccionar expresiones usando as: + + + + + + Esto es lo más útil cuando se usa junto con select new map: + + + + + + Esta consulta devuelve un Map de aliases a valores seleccionados. + + + + + + Funciones de agregación + + + Las consultas HQL pueden incluso devolver resultados de funciones de agregación sobre propiedades: + + + + + + + + Las funciones de agregación soportadas son + + + + + + avg(...), sum(...), min(...), max(...) + + + + + count(*) + + + + + count(...), count(distinct ...), count(all...) + + + + + + Puedes usar operadores aritméticos, concatenación, y funciones SQL reconocidas en la cláusula select: + + + + + + + + Las palabras clave distinct y all pueden ser usadas y tienen las misma + semántica que en SQL. + + + + + + + + Consultas polimórficas + + + Una consulta como: + + + + + + devuelve instancias no sólo de Cat, sino también de subclases como + DomesticCat. Las consultas de Hibernate pueden mencionar cualquier + clase o interface Java en la cláusula from. 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. + + + + + + La interface Named podría ser implementada por varias clases persistentes: + + + + + + Nota que estas dos últimas consultas requerirán más de un SELECT SQL. Esto significa + que la cláusula order by no ordenará correctamente todo el conjunto resultado. + (Significa además que no puedes llamar estas consulta usando Query.scroll().) + + + + + + La cláusula where + + + 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: + + + + + + Si existe un alias, usan un nombre cualificado de propiedad: + + + + + + devuelve las instancias de Cat llamadas 'Fritz'. + + + + + + devolverá todas las instancias de Foo para las cuales exista una instancia + de bar con una propiedad date igual a la propiedad + startDate del Foo. Las expresiones de ruta compuestas hacen + la cláusula where extremadamente potente. Considera: + + + + + + Esta consulta se traduce en una consulta SQL con una unión de tabla (interna). Si fueses a escribir algo como + + + + + + terminarías con una consulta que requeriría cuatro uniones de tablas en SQL. + + + + El operador = puede ser usado para comparar no sólo propiedades, sino también instancias: + + + + + + + + La propiedad especial (en minúsculas) id puede ser usada para referenciar el identificador + único de un objeto. (También puedes usar su nombre de propiedad.) + + + + + + La segunda consulta es eficiente. ¡No se requiere ninguna unión de tablas! + + + + También pueden ser usadas las propiedades de identificadores compuestos. Supón que Person + tiene un identificador compuesto consistente en country y medicareNumber. + + + + + + + + Una vez más, la segunda consulta no requiere ninguna unión de tablas. + + + + Asimismo, la propiedad especial class 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. + + + + + + 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 store.owner + es una entidad con un componente address + + + + + + Un tipo "any" tiene las propiedades especiales id y class, + permiténdonos expresar un join en la siguiente forma (donde AuditLog.item es una + propiedad mapeada con <any>). + + + + + + Nota que log.item.class y payment.class harían referencia a + los valores de columnas de base de datos completamente diferentes en la consulta anterior. + + + + + + Expresiones + + + Las expresiones permitidas en la cláusula where incluyen la mayoría del tipo de cosas + que podrías escribir en SQL: + + + + + + operadores matemáticos +, -, *, / + + + + + operadores de comparación binarios =, >=, <=, <>, !=, like + + + + + operadores lógicos and, or, not + + + + + Paréntesis ( ), indicando agrupación + + + + + in, + not in, + between, + is null, + is not null, + is empty, + is not empty, + member of y + not member of + + + + + Caso "simple", case ... when ... then ... else ... end, + y caso "buscado", case when ... then ... else ... end + + + + + concatenación de cadenas ...||... o concat(...,...) + + + + + current_date(), current_time(), + current_timestamp() + + + + + second(...), minute(...), + hour(...), day(...), + month(...), year(...), + + + + + Cualquier función u operador definido por EJB-QL 3.0: substring(), trim(), + lower(), upper(), length(), locate(), abs(), sqrt(), bit_length(), mod() + + + + + coalesce() y nullif() + + + + + str() para convertir valores numéricos o temporales a una cadena legible. + + + + + cast(... as ...), donde el segundo argumento es el nombre de un tipo Hibernate + , y extract(... from ...) si cast() y + extract() fuesen soportados por la base de datos subyacente. + + + + + + + la función index() de HQL, que se aplica a alias de una colección + indexada unida. + + + + + funciones de HQL que tomen expresiones de ruta valuadas en colecciones: size(), + minelement(), maxelement(), minindex(), maxindex(), junto a las funciones especiales + elements() and indices que pueden ser cuantificadas usando + some, all, exists, any, in. + + + + + + Cualquier función escalar SQL soportada por la base de datos como sign(), + trunc(), rtrim(), sin() + + + + + parámetros posicionales JDBC ? + + + + + parámetros con nombre :name, :start_date, :x1 + + + + + literales SQL 'foo', 69, 6.66E+2, + '1970-01-01 10:00:01.0' + + + + + constantes Java public static final eg.Color.TABBY + + + + + + in y between pueden usarse como sigue: + + + + + + + + y pueden escribirse las formas negadas + + + + + + + + Asimismo, is null y is not null pueden ser usadas para comprobar + valores nulos. + + + + Los booleanos pueden ser fácilmente usados en expresiones declarando substituciones de consulta HQL + en la configuración de Hibernate: + + + true 1, false 0]]> + + + Esto remplazará las palabras clave true y false con los literales + 1 y 0 en el SQL traducido de este HQL: + + + + + + Puedes comprobar el tamaño de una colección con la propiedad especial size, o la función + especial size(). + + + 0]]> + + 0]]> + + + Para colecciones indexadas, puedes referirte a los índices máximo y mínimo usando las funciones + minindex y maxindex. Similarmente, puedes referirte a los elementos + máximo y mínimo de una colección de tipo básico usando las funciones + minelement y maxelement. + + + current_date]]> + + 100]]> + + 10000]]> + + + Las funciones SQL any, some, all, exists, in están soportadas cuando se les pasa + el conjunto de elementos o índices de una colección (funciones elements y + indices) o el resultado de una subconsulta (ver debajo). + + + + + + + + + all elements(p.scores)]]> + + + + + Nota que estas construcciones - size, elements, + indices, minindex, maxindex, + minelement, maxelement - pueden ser usadas solamente + en la cláusula where en Hibernate3. + + + + Los elementos de colecciones indexadas (arrays, listas, mapas) pueden ser referidos por índice + (en una cláusula where solamente): + + + + + + + + + + + + La expresión dentro de [] puede incluso ser una expresión aritmética. + + + + + + HQL provee además el función prefabricada index(), para elementos de una + asociación uno-a-muchos o colección de valores. + + + + + + Pueden usarse las funciones SQL escalares soportadas por la base de datos subyacente + + + + + + 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: + + + + + + Ayuda: algo como + + + + + + + + La cláusula order by + + + La lista devuelta por una consulta puede ser ordenada por cualquier propiedad de una clase devuelta + o componentes: + + + + + + Los asc o desc opcionales indican ordenamiento ascendente o + descendente respectivamente. + + + + + La cláusula group by + + + Una consulta que devuelve valores agregados puede ser agrupada por cualquier propiedad de una clase + devuelta o componentes: + + + + + + + + Se permite también una cláusula having. + + + + + + Las funciones y funciones de agregación SQL están permitidas en las cláusulas + having y order by, si están soportadas por la base de datos + subyacente (por ejemplo, no en MySQL). + + + 100 +order by count(kitten) asc, sum(kitten.weight) desc]]> + + + Nota que ni la cláusula group by ni la cláusula order by pueden + contener expresiones aritméticas. + + + + + + Subconsultas + + + 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). + + + ( + select avg(cat.weight) from DomesticCat cat +)]]> + + + + + + + + + Para las subconsultas con más de una expresión en la lista de selección, puedes usar un constructor + de tuplas: + + + + + + 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: + + + + + + Que es equivalente a la más verborrágica: + + + + + + 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. + + + + + + Ejemplos de HQL + + + 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! + + + + 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 ORDER, ORDER_LINE, PRODUCT, + CATALOG and PRICE tiene cuatro joins interiores y una subselect + (no correlacionada). + + + = 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]]> + + + ¡Qué monstruo! Realmente, en la vida real, no estoy muy afilado en subconsultas, de modo que mi + consulta fue realmente algo como esto: + + + :minAmount +order by sum(price.amount) desc]]> + + + La próxima consulta cuenta el número de pagos en cada estado, excluyendo todos los pagos + en el estado AWAITING_APPROVAL 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 PAYMENT, PAYMENT_STATUS y + PAYMENT_STATUS_CHANGE. + + + 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]]> + + + Si hubiese mapeado la colección statusChanges como una lista, en vez de un conjunto, + la consulta habría sido mucho más simple de escribir. + + + PaymentStatus.AWAITING_APPROVAL + or payment.statusChanges[ maxIndex(payment.statusChanges) ].user <> :currentUser +group by status.name, status.sortOrder +order by status.sortOrder]]> + + + La próxima consulta usa la función isNull() 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 ACCOUNT, PAYMENT, PAYMENT_STATUS, + ACCOUNT_TYPE, ORGANIZATION y ORG_USER. + + + + + + Para algunas bases de datos, necesitaríamos eliminar la subselect (correlacionada). + + + + + + + + Sentencias UPDATE y DELETE masivas + + + HQL soporta ahora sentencias UPDATE y DELETE en HQL. + Ver para detalles. + + + + + Consejos y Trucos + + + Puedes contar el número de resultados de una consulta sin devolverlos realmente: + + + + + + Para ordenar un resultado por el tamaño de una colección, usa la siguiente consulta: + + + + + + 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: + + + = 1]]> + + + Si tu base de datos no soporta subselects, usa la siguiente consulta: + + + = 1]]> + + + Como esta solución no puede devolver un User con cero mensajes debido a la unión interior, + la siguiente forma es también útil: + + + + + + Las propiedades de un JavaBean pueden ser ligadas al parámetros de consulta con nombre: + + + + + + Las colecciones son paginables usando la interface Query con un filtro: + + + + + + Los elementos de colección pueden ser ordenados o agrupados usando un filtro de consulta: + + + + + + Puedes hallar el tamaño de una colección sin inicializarla: + + + + + + + + diff --git a/documentation/manual/es-ES/src/main/docbook/content/query_sql.xml b/documentation/manual/es-ES/src/main/docbook/content/query_sql.xml new file mode 100644 index 0000000000..5bfebad7cd --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/content/query_sql.xml @@ -0,0 +1,477 @@ + + SQL Nativo + + + 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 + CONNECT en Oracle. Provee además una clara ruta de migración desde una aplicación + basada en SQL/JDBC directo a Hibernate. + + + + Hibernate3 te permite especificar SQL escrito a mano (incluyendo procedimientos almacenados) para todas + las operaciones de creación, actualización, borrado y carga. + + + + Creando una <literal>Query</literal> de SQL nativo + + + Las consultas SQL se controlan por medio de la interface SQLQuery, que se obtiene + llamando a Session.createSQLQuery(). + + + + + + Esta consulta especificada: + + + + + + la cadena de consulta SQL, con un lugar para que Hibernate inyecte los alias de columnas + + + + + la entidad devuelta por la consulta, y sus alias de tablas SQL + + + + + + El método addEntity() asocia alias de tablas SQL con clases de entidad, + y determina la forma del conjunto resultado de la consulta. + + + + El método addJoin() puede ser usado para cargar asociaciones a otras entidades y + colecciones. + + + + + + Una consulta SQL nativa podría devolver un valor escalar simple o una combinación de escalares y entidades. + + + + + + + + + Alias y referencias de propiedad + + + La notación {cat.*} 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 Cats de una tabla diferente (cat_log) 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. + + + La sintáxis {} no es requerida para consultas con nombre. + Ver + + + + + + Nota: si listas cada propiedad explícitamente, ¡debes incluir todas las + propiedades de la clase y sus subclases! + + + + + + Consultas SQL con nombre + + + 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, no + necesitamos llamar a addEntity(). + + + + + SELECT person.NAME AS {person.name}, + person.AGE AS {person.age}, + person.SEX AS {person.sex} + FROM PERSON person + WHERE person.NAME LIKE :namePattern +]]> + + + + + Los elementos <return-join> y <load-collection> + se usan para unir asociaciones y definir consultas que inicialicen colecciones, respectivamente. + + + + + + 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 +]]> + + + Una consulta SQL con nombre puede devolver un valor escalar. Debes especificar el alias de columna y + tipo Hibernate usando el elementp <return-scalar>: + + + + + + SELECT p.NAME AS name, + p.AGE AS age, + FROM PERSON p WHERE p.NAME LIKE 'Hiber%' +]]> + + + Usando return-property para especificar explícitamente nombres de columna/alias + + + Con <return-property> puedes decirle explícitamente a Hibernate qué + alias de columna usar, en vez de usar la sintáxis {} para dejar que Hibernate + inyecte sus propios alias. + + + + + + + + + SELECT person.NAME AS myName, + person.AGE AS myAge, + person.SEX AS mySex, + FROM PERSON person WHERE person.NAME LIKE :name + +]]> + + + <return-property> también trabaja con múltiples columnas. Esto resuelve una + limitación de la sintáxis {}, la cual no puede permitir un control fino de propiedades + multi-columna. + + + + + + + + + + + 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 +]]> + + + Nota que en este ejemplo hemos usado <return-property> en combinación con + la sintáxis {} para inyección, permitiendo a los usuarios elejir cómo quieren + referirse a las columnas y propiedades. + + + + Si tu mapeo tiene un discriminador debes usar <return-discriminator> + para especificar la columna discriminadora. + + + + + Usando procedimientos almacenados para consultar + + + 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 usar esta consulta en Hibernate necesitas mapearla por medio de una consulta con nombre. + + + + + + + + + + + + + + + + { ? = call selectAllEmployments() } +]]> + + + Nota que los procedimientos almacenados sólo devuelven escalares y entidades. + No están soportados <return-join> y <load-collection>. + + + + Reglas/limitaciones para usar procedimientos almacenados + + + 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 session.connection(). 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. + + + + Las consultas de procedimientos almacenados no pueden ser paginadas con + setFirstResult()/setMaxResults(). + + + + Para Oracle se aplican las siguientes reglas: + + + + + + El procedimiento debe devolver un conjunto resultado. Esto se hace devolviendo un + SYS_REFCURSOR en Oracle 9 o 10. En Oracle necesitas definir un + tipo REF CURSOR. + + + + + La forma recomendada es { ? = call procName(<parameters>) } o + { ? = call procName } (esto es más una regla de Oracle que una regla de Hibernate). + + + + + + Para Sybase o MS SQL server se aplican las siguientes reglas: + + + + + + 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. + + + + + Si habilitas SET NOCOUNT ON en tu procedimiento será probablemente más + eficiente, pero esto no es un requerimiento. + + + + + + + + + + SQL personalizado para crear, actualizar y borrar + + + 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 <sql-insert>, + <sql-delete>, y <sql-update> sobrescriben + estas cadenas: + + + + + + + + INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? ) + UPDATE PERSON SET NAME=UPPER(?) WHERE ID=? + DELETE FROM PERSON WHERE ID=? +]]> + + + 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. + + + + Los procedimientos almacenados son soportados si está establecido el atributo + callable: + + + + + + + + {call createPerson (?, ?)} + {? = call deletePerson (?)} + {? = call updatePerson (?, ?)} +]]> + + + El orden de los parámetros posicionales son actualmente vitales, ya que deben estar en la + misma secuencia en que las espera Hibernate. + + + + Puedes ver el orden esperado habilitando el registro de depuración para el nivel + org.hibernate.persister.entity. 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.) + + + + 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: + + + + + + + + + SQL personalizado para carga + + + Puedes también declarar tu propias consultas SQL (o HQL) para cargar entidades: + + + + + SELECT NAME AS {pers.name}, ID AS {pers.id} + FROM PERSON + WHERE ID=? + FOR UPDATE +]]> + + + 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: + + + + + + + + +]]> + + + Esto incluso funciona con procedimientos almacenados. + + + + Puedes incluso definit una consulta para la carga de colecciones: + + + + + + +]]> + + + + SELECT {emp.*} + FROM EMPLOYMENT emp + WHERE EMPLOYER = :id + ORDER BY STARTDATE ASC, EMPLOYEE ASC +]]> + + + Podrías incluso definir un cargador de entidades que cargue una colección por + recuperación por unión (join fetching): + + + + + + SELECT NAME AS {pers.*}, {emp.*} + FROM PERSON pers + LEFT OUTER JOIN EMPLOYMENT emp + ON pers.ID = emp.PERSON_ID + WHERE ID=? +]]> + + + + \ No newline at end of file diff --git a/documentation/manual/es-ES/src/main/docbook/content/quickstart.xml b/documentation/manual/es-ES/src/main/docbook/content/quickstart.xml new file mode 100644 index 0000000000..a526c45b17 --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/content/quickstart.xml @@ -0,0 +1,666 @@ + + Comienzo rápido con Tomcat + + + Empezando con Hibernate + + + 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. + + + + Primero, tenemos que copiar todas las bibliotecas requeridas a la instalación + de Tomcat. Usamos un contexto web separado (webapps/quickstart) + para este tutorial, de modo que tenemos que considerar tanto la ruta de búsqueda + de bibliotecas global (TOMCAT/common/lib) como también + el cargador de clases a nivel de contexto en webapps/quickstart/WEB-INF/lib + (para ficheros JAR) y webapps/quickstart/WEB-INF/classes. + Nos referiremos a ambos niveles de cargador de clases como el classpath global y el classpath + de contexto, respectivamente. + + + + Ahora, copia las bibliotecas a los dos classpaths: + + + + + + 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 + pg74jdbc3.jar (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. + + + + + 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 + WEB-INF/lib y tus propias clases y ficheros de + configuración/propiedades a WEB-INF/classes. + Ambos directorios están a nivel del classpath de contexto por defecto. + + + + + Hibernate está empaquetado como una biblioteca JAR. El fichero + hibernate3.jar 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 + lib/. Ver . Copia las + bibliotecas de terceros requeridas al classpath de contexto. + + + + + + + Bibliotecas de terceros de Hibernate + + + + + + + + Biblioteca + + + Descripción + + + + + + + antlr (requerida) + + + Hibernate usa ANTLR para producir analizadores de consultas, + esta biblioteca también se necesita en tiempo de ejecución. + + + + + dom4j (requerida) + + + Hibernate usa dom4j para analizar ficheros de configuración + XML y ficheros de metadatos de mapeo XML. + + + + + CGLIB, asm (requerida) + + + 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). + + + + + Commons Collections, Commons Logging (requeridas) + + + Hibernate usa varias bibliotecas de utilidad del proyecto + Jakarta Commons de Apache. + + + + + EHCache (requerida) + + + 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. + + + + + Log4j (opcional) + + + 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 log4j.properties + 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 src/) a tu classpath de contexto si quieres + ver que ocurre tras escénas. + + + + + ¿Requerida o no? + + + Echa una mirada al fichero lib/README.txt 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). + + + + +
+ + + 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, TOMCAT/conf/server.xml: + + + + + + + factory + org.apache.commons.dbcp.BasicDataSourceFactory + + + + + url + jdbc:postgresql://localhost/quickstart + + + driverClassNameorg.postgresql.Driver + + + username + quickstart + + + password + secret + + + + + maxWait + 3000 + + + maxIdle + 100 + + + maxActive + 10 + + +]]> + + + El contexto que configuramos en este ejemplo se llama quickstart, + su base es el directorio TOMCAT/webapp/quickstart. Para acceder + a cualquier servlet, llama a la ruta http://localhost:8080/quickstart + en tu navegador (por supuesto, agregando el nombre del servlet como se mapee en tu + web.xml). Puedes también ir más allá y crear + ahora un servlet simple que tenga un método process() + vacío. + + + + Tomcat provee ahora conexiones a través de JNDI en + java:comp/env/jdbc/quickstart. 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. + + + + 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 (WEB-INF/classes), como + hibernate.cfg.xml: + + + + + + + + + + java:comp/env/jdbc/quickstart + false + org.hibernate.dialect.PostgreSQLDialect + + + + + + +]]> + + + 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. + + + + Una SessionFactory 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 Configuration + y SessionFactory en tu aplicación. + + + + El último elemento del hibernate.cfg.xml + declara Cat.hbm.xml como el nombre de un fichero + de mapeo XML para la clase persistente Cat. Este + fichero contiene los metadatos para el mapeo de la clase POJO + Cat 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. + + +
+ + + Primera clase persistente + + + 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): + + + + + + Hibernate no está restringido en su uso de tipos de propiedad, todos + los tipos y tipos primitivos del JDK de Java (como String, + char y Date) pueden ser mapeados, incluyendo + clases del framework de colecciones de Java. Puedes mapearlos como valores, + colecciones de valores, o asociaciones a otras entidades. El id + es una propiedad especial que representa el identificador de base de datos (clave + primaria) de la clase. Es altamente recomendado para entidades como un + Cat. Hibernate puede usar identificadores sólo + internamente, pero perderíamos algo de la flexibilidad en nuestra + arquitectura de aplicación. + + + + 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. + + + + + + Mapeando el gato + + + El fichero de mapeo Cat.hbm.xml 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. + + + + + + + + + + + + + + + + + + + + + + + + + + +]]> + + + 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 + catA.getId().equals(catB.getId()) es verdadero. Este concepto + se llama identidad de base de datos (database identity). + 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 CAT_ID de la tabla + CAT para el valor identificador generado por Hibernate + (como una clave primaria de la tabla). + + + + Todas las demás propiedades de Cat son mapeadas a la + misma tabla. En el caso de la propiedad name, 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 SchemaExport 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 CAT en la base de datos se ve así como: + + + + + + Ahora debes crear esta tabla manualmente en tu base de datos, y luego leer el + si quieres automatizar este paso con la + herramienta hbm2ddl. Esta herramienta puede crear un + DDL SQL completo, incluyendo definición de tablas, restricciones + personalizadas de tipo de columnas, restricciones de unicidad e índices. + + + + + + Jugando con gatos + + + Ahora estamos listos para comenzar la Session de Hibernate. + Es el manejador de persistencia que usamos para almacenar + y traer Cats hacia y desde la base de datos. Pero primero, + tenemos que obtener una Session (unidad de trabajo de Hibernate) + de la SessionFactory: + + + + + + La llamada a configure() carga el fichero de + configuración hibernate.cfg.xml e + inicializa la instancia de Configuration. + Puedes establecer otras propiedades (e incluso cambiar los metadatos de mapeo) + accediendo a la Configuration antes + que construyas la SessionFactory (que es inmutable). + ¿Dónde creamos la SessionFactory y cómo + accedemos a ella en nuestra aplicación? + + + + Una SessionFactory usualmente se construye una vez, + por ejemplo, al arrancar con un servlet load-on-startup. + 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 Singleton, de modo que podamos acceder a la + SessionFactory 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 + SessionFactory. + + + + Implementamos una clase de ayuda HibernateUtil: + + + + + + Esta clase no sólo cuida de la SessionFactory + con su inicializador static, sino que además tiene una variable + ThreadLocal que tiene la Session + 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 + HibernateUtil más compleja y potente puede + encontrarse en CaveatEmptor, http://caveatemptor.hibernate.org/ + + + + Una SessionFactory es segura entre hebras, muchas hebras pueden + acceder a ella concurrentemente y pedirle Sessions. Una + Session no es un objeto seguro entre hebras que representa + una sola unidad-de-trabajo con la base de datos. Las Sessions + se abren desde una SessionFactory y son cerradas cuando + todo el trabajo está completo. Un ejemplo en el método + process() de tu servlet podría parecerse a esto + (sin manejo de excepciones): + + + + + + En una Session, 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 Transaction 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. + + + + Observa que puedes llamar HibernateUtil.currentSession(); + tantas veces como quieras, siempre obtendrás la Session + actual de esta hebra. Tienes que asegurarte que la Session + 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 Session 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. + + + + 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: + + + + + + Hibernate también ofrece una API consulta por criterios + orientada a objetos que puede ser usada para formular consultas de tipo seguro. + Por supuesto, Hibernate usa PreparedStatements 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 Session + en casos raros. + + + + + + Finalmente + + + 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. + + + + 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 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 + + + + +
diff --git a/documentation/manual/es-ES/src/main/docbook/content/session_api.xml b/documentation/manual/es-ES/src/main/docbook/content/session_api.xml new file mode 100644 index 0000000000..c8d23f2e87 --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/content/session_api.xml @@ -0,0 +1,1224 @@ + + Trabajando con objetos + + + 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 manejo de estado de + objetos. Esto es, al contrario del manejo de sentencias + SQL en capas comunes de persistencia JDBC/SQL, una vista de la persistencia + en aplicaciones Java muy natural y orientada a objetos. + + + + En otras palabras, los desarroladores de aplicaciones Hibernate deben siempre + pensar en el estado 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. + + + + Estados de objeto de Hibernate + + + Hibernate define y soporta los siguientes estados de objeto: + + + + + + Transitorio - un objeto es transitorio si ha sido + recién instanciado usando el operador new, y no está + asociado a una Session 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 Session de Hibernate para hacer un objeto + persistente (y deja que Hibernate cuide de las sentencias SQL que necesitan + ejecutarse para esta transición). + + + + + Persistente - 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 Session. 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 UPDATE manuales, o sentencias DELETE + cuando un objeto debe ser hecho transitorio. + + + + + Separado (detached) - una instancia separada es un objeto + que ha sido hecho persistente, pero su Session 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 Session 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 transaccciones + de aplicación, es decir, una unidad de trabajo desde el punto de vista + del usuario. + + + + + + Discutiremos ahora los estados y transiciones de estados (y los métodos de Hibernate que + disparan una transición) en más detalle: + + + + + + Haciendo los objetos persistentes + + + Las instancias recién instanciadas de una clase persistente son consideradas + transitorias por Hibernate. Podemos hacer una instancia + transitoria persistente asociándola con una sesión: + + + + + + Si Cat tiene un identificador generado, el identificador es + generado y asignado al cat cuando se llama a save(). + Si Cat tiene un identificador assigned, + o una clave compuesta, el identificador debe ser asignado a la instancia de + cat antes de llamar a save(). Puedes también + usar persist() en vez de save(), con la semántica + definida en el temprano borrador de EJB3. + + + + Alternativamente, puedes asignar el identificador usando una versión sobrecargada + de save(). + + + + + + Si el objeto que haces persistente tiene objetos asociados (por ejemplo, + la colección kittens en el ejemplo anterior), estos + objetos pueden ser hechos persistentes en cualquier orden que quieras + a menos que tengas una restricción NOT NULL sobre una + columna clave foránea. Nunca hay riesgo de violar restricciones de clave + foránea. Sin embargo, podrías violar una restricción NOT NULL + si llamas a save() sobre objetos en orden erróneo. + + + + Usualmente no te preocupas con este detalle, pues muy probablemente usarás + la funcionalidad de persistencia transitiva de Hibernate + para salvar los objetos asociados automáticamente. Entonces, ni siquiera ocurren + violaciones de restricciones NOT NULL - Hibernate cuidará de todo. + La persistencia transitiva se discute más adelante en este capítulo. + + + + + + Cargando un objeto + + + Los métodos load() de Session te brindan + una forma de traer una instancia persistente si ya saves su identificador. + load() toma un objeto clase y cargará el estado dentro de + una instancia recién instanciada de esta clase, en estado persistente. + + + + + + + + Alternativamente, puedes cargar estado dentro de una instancia dada: + + + + + + Nota que load() lanzará una excepción irrecuperable si no + hay una fila correspondiente en base de datos. Si la clase es mapeada con un + proxy, load() 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 batch-size + para el mapeo de la clase. + + + + Si no tienes certeza que exista una fila correspondiente, debes usar el + método get(), que llama a la base de datos inmediatamente + y devuelve nulo si no existe una fila correspondiente. + + + + + + Puedes incluso cargar un objeto usando un SELECT ... FOR UPDATE de SQL, + usando un LockMode. Ver la documentación de la API para más + información. + + + + + + Ten en cuenta que ninguna instancia asociada o colección contenida es + selecciona FOR UPDATE, a menos que decidas especificar + lock o all como un estilo de cascada para la + asociación. + + + + Es posible volver a cargar un objeto y todas sus colecciones en cualquier momento, + usando el método refresh(). Esto es útil cuando se usan disparadores de + base de datos para inicializar algunas de las propiedades del objeto. + + + + + + Una cuestión importante aparece usualmente en este punto: ¿Cuánto carga Hibernate de + la base de datos y cuántos SELECTs de SQL usará? Esto depende de la + estrategia de recuperación y se explica en . + + + + + + Consultando + + + 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. + + + + Ejecutando consultas + + + Las consultas HQL y SQL nativas son representadas con una instancia de + org.hibernate.Query. 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 Query + usando la Session actual: + + + + + + Una consulta se ejecuta usualmente invocando a list(), + 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 uniqueResult() + ofrece un atajo si sabes que tu consulta devolverá sólo un objeto. + + + + Iterando los resultados + + + Ocasionalmente, podrías ser capaz de lograr mejor rendimiento al ejecutar la consulta + usando el método iterate(). 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é, iterate() + será más lento que list() y podría requerir muchas llamadas a la + base de datos para una consulta simple, usualmente 1 para la + selección inicial que solamente devuelve identificadores, y n + selecciones adicionales para inicializar las instancias reales. + + + + + + + Consultas que devuelven tuplas + + + Las consultas de Hibernate a veces devuelven tuplas de objetos, en cuyo caso + cada tupla se devuelve como un array: + + + + + + + + Resultados escalares + + + Las consultas pueden especificar una propiedad de una clase en la cláusula + select. Pueden incluso llamar a funciones de agregación SQL. + Las propiedades o agregaciones son considerados resultados "escalares" + (y no entidades en estado persistente). + + + + + + + + Ligación de parámetros + + + Se proveen métodos en Query para ligar valores a + parámetros con nombre o parámetros ? de estilo JDBC. + Al contrario de JDBC, Hibernate numera los parámetros desde cero. + Los parámetros con nombre son identificadores de la forma :name + en la cadena de la consulta. Las ventajas de los parámetros con nombre son: + + + + + + los parámetros con nombre son insensibles al orden en que aparecen + en la cadena de consulta + + + + + pueden aparecer múltiples veces en la misma consulta + + + + + son auto-documentados + + + + + + + + + + + + + + Paginación + + + 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 Query: + + + + + + Hibernate sabe cómo traducir este límite de consulta al SQL nativo de tu + DBMS. + + + + + + Iteración scrollable + + + Si tu driver JDBC soporta ResultSets scrollables, la + interface Query puede ser usada para obtener un objeto + ScrollableResults, que permite una navegación flexible + de los resultados de consulta. + + + i++ ) && cats.next() ) pageOfCats.add( cats.get(1) ); + +} +cats.close()]]> + + + Nota que se requiere una conexión de base de datos abierta (y cursor) para esta + funcionalidad, usa setMaxResult()/setFirstResult() + si necesitas la funcionalidad de paginación fuera de línea. + + + + + + Externalizando consultas con nombre + + + Puedes además definir consultas con nombre en el documento de mapeo. + (Recuerda usar una sección CDATA si tu consulta + contiene caracteres que puedan ser interpretados como etiquetado.) + + + ? +] ]>]]> + + + La ligación de parámetros y ejecución se hace programáticamente: + + + + + + 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. + + + + + + + + Filtrando colecciones + + Un filtro 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 + this, significando el elemento de colección actual. + + + + + + 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). + + + + Observa que los filtros no requieren una cláusula from (aunque pueden + tener uno si se requiere). Los filtros no están limitados a devolver los elementos de + colección por sí mismos. + + + + + + Incluso una consulta de filtro vacío es útil, por ejemplo, para cargar un + subconjunto de elementos en una colección enorme: + + + + + + + + Consultas de criterios + + + 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 Criteria + para estos casos: + + + + + + Las APIs de Criteria y la asociada Example + son discutidas en más detalle en . + + + + + + Consultas en SQL nativo + + + Puedes expresar una consulta en SQL, usando createSQLQuery() y + dejando que Hibernate cuide del mapeo de los conjuntos resultado a objetos. + Nota que puedes llamar en cualquier momento a session.connection() y + usar la Connection JDBC directamente. Si eliges usar la API de + Hibernate, debes encerrar los alias de SQL entre llaves: + + + + + + + + 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 . + + + + + + + + Modificando objetos persistentes + + + Las instancias persistentes transaccionales (es decir, objetos cargados, + creados o consultados por la Session) pueden ser manipulados por la + aplicación y cualquier cambio al estado persistente será persistido cuando la Session + sea limpiada (flushed) (discutido más adelante en este capítulo). No hay + necesidad de llamar un método en particular (como update(), 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 load(), + y entonces manipularlo directamente, mientras la Session está abierta: + + + + + + A veces este modelo de programación es ineficiente pues podría requerir una + SELECT de SQL (para cargar un objeto) y un UPDATE + 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). + + + + Nota que Hibernate no ofreve su propia API para ejecución directa de + sentencias UPDATE o DELETE. Hibernate es un + servicio de gestión de estado, no tienes que pensar en + sentencias para usarlo. JDBC es una API perfecta para ejecutar + sentencias SQL; puedes obtener una Connection JDBC en cualquier + momento llamando a session.connection(). 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 + por algunos trucos de operación en lote (batch) posibles. + + + + + + + Modificando objetos separados + + + 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". + + + + Hibernate soporta este modelo al proveer re-unión de instancias separadas usando + los métodos Session.update() o Session.merge(): + + + + + + Si el Cat con identificador catId ya hubiera + sido cargado por secondSession cuando la aplicación intentó + volver a unirlo, se habría lanzado una excepción. + + + + Usa update() si no estás seguro que la sesión tenga + una instancia ya persistente con el mismo identificador, y merge() + si quieres fusionar tus modificaciones en cualquier momento sin consideración del + estado de la sesión. En otras palabras, update() 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. + + + + La aplicación debe actualizar individualmente las instancias separadas alcanzables + por la instancia separada dada llamando a update(), si y + sólo si quiere que sus estados sean también actualizados. + Esto puede, por supuesto, ser automatizado usando persistencia transitiva, + ver . + + + + El método lock() 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! + + + + + + Nota que lock() puede ser usado con varios LockModes, + 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 lock(). + + + + Se discuten otros modelos para unidades de trabajo largas en . + + + + + + Detección automática de estado + + + 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 saveOrUpdate() implementa esta funcionalidad. + + + + + + El uso y semántica de saveOrUpdate() 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 update(), + saveOrUpdate(), o merge(). Algunas aplicaciones + enteras nunca usarán ninguno de estos métodos. + + + + Usualmente update() o saveOrUpdate() se usan en + el siguiente escenario: + + + + + + la aplicación carga un objeto en la primera sesión + + + + + el objeto es pasado a la capa de UI + + + + + se hacen algunas modificaciones al objeto + + + + + el objeto se pasa abajo de regreso a la capa de negocio + + + + + la aplicación hace estas modificaciones persistentes llamando + a update() en una segunda sesión + + + + + + saveOrUpdate() hace lo siguiente: + + + + + + si el objeto ya es persistente en esta sesión, no hace nada + + + + + si otro objeto asociado con la sesión tiene el mismo identificador, + lanza una excepción + + + + + si el objeto no tiene ninguna propiedad identificadora, lo salva llamando a + save() + + + + + si el identificador del objeto tiene el valor asignado a un objeto recién + instanciado, lo salva llamando a save() + + + + + si el objeto está versionado (por un <version> o + <timestamp>), y el valor de la propiedad de versión + es el mismo valor asignado a una objeto recién instanciado, lo salva llamando + a save() + + + + + en cualquier otro caso se actualiza el objeto llamando a update() + + + + + + y merge() es muy diferente: + + + + + + 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 + + + + + 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 + + + + + la instancia persistente es devuelta + + + + + la instancia dada no resulta ser asociada a la sesión, permanece separada + + + + + + + + Borrando objetos persistentes + + + Session.delete() 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 delete() como hacer transitoria una instancia persistente. + + + + + + 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 + NOT NULL sobre una columna clave foránea borrando objetos + en un orden erróneo, por ejemplo, si borras el padre, pero olvidas borrar los + hijos. + + + + + + Replicando objetos entre dos almacénes de datos diferentes + + + 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. + + + + + + El ReplicationMode determina cómo replicate() + tratará los conflictos con filas existentes en la base de datos. + + + + + + ReplicationMode.IGNORE - ignora el objeto cuando existe una fila + de base de datos con el mismo identificador + + + + + ReplicationMode.OVERWRITE - sobrescribe cualquier fila de base de + datos existente con el mismo identificador + + + + + ReplicationMode.EXCEPTION - lanza una excepción si existe una fila + de base de datos con el mismo identificador + + + + + ReplicationMode.LATEST_VERSION - 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 + + + + + + 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. + + + + + + Limpiando (flushing) la sesión + + + Cada tanto, la Session 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, limpieza (flush), ocurre por defecto en los siguientes + puntos + + + + + + antes de algunas ejecuciones de consulta + + + + + desde org.hibernate.Transaction.commit() + + + + + desde Session.flush() + + + + + + Las sentencias SQL son liberadas en el siguiente orden + + + + + + todas las inserciones de entidades, en el mismo orden que los objetos + correspondientes fueron salvados usando Session.save() + + + + + todas las actualizaciones de entidades + + + + + todas los borrados de colecciones + + + + + todos los borrados, actualizaciones e inserciones de elementos de colección + + + + + todas las inserciones de colecciones + + + + + todos los borrados de entidades, en el mismo orden que los objetos + correspondientes fueron borrados usando Session.delete() + + + + + + (Una excepción es que los objetos que usan generación de ID native + se insertan cuando son salvados.) + + + + Excepto cuando llamas explícitamente a flush(), no hay en absoluto + garantías sobre cuándo la Session ejecuta las + llamadas JDBC. sólo sobre el orden en que son ejecutadas. Sin embargo, + Hibernate garantiza que los métodos Query.list(..) nunca devolverán datos + añejos o erróneos. + + + + Es posible cambiar el comportamiento por defecto de modo que la limpieza (flush) + ocurra menos frecuentemente. La clase FlushMode tres modos + diferentes: sólo en tiempo de compromiso (y sólo cuando se use la API de + Transaction de Hibernate), limpieza automática usando la rutina + explicada, o nunca limpiar a menos que se llame a flush() + explícitamente. El último modo es útil para unidades de trabajo largas, donde una + Session se mantiene abierta y desconectada por largo tiempo + (ver ). + + + + + + 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 . + + + + + + Persistencia transitiva + + + 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: + + + + 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. + + + + 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 persistencia por + alcance. + + + + Para cada operación básica de la sesión de Hibernate - incluyendo persist(), merge(), + saveOrUpdate(), delete(), lock(), refresh(), evict(), replicate() - hay un estilo + de cascada correspondiente. Respectivamente, los estilos de cascada se llaman create, + merge, save-update, delete, lock, refresh, evict, replicate. 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: + + + ]]> + + + Los estilos de cascada pueden combinarse: + + + ]]> + + + Puedes incluso usar cascade="all" para especificar que todas + las operaciones deben ser tratadas en cascada a lo largo de la asociación. El por defecto + cascade="none" especifica que ninguna operación será tratada en cascada. + + + + Un estilo de cascada especial, delete-orphan, se aplica sólo a + asociaciones uno-a-muchos, e indica que la operación delete() debe + aplicarse a cualquier objeto hijo que sea quitado de la asociación. + + + + + Recomendaciones: + + + + + + Usualmente no tiene sentido habilitar el tratamiento en cascada a una asociación + <many-to-one> o <many-to-many>. + El tratamiento en cascada es frecuentemente útil para las asociaciones + <one-to-one> y <one-to-many>. + associations. + + + + + Si la esperanza de vida de los objetos hijos está ligada a la eesperanza de + vida del objeto padre, házlo un objeto de ciclo de vida + especificando cascade="all,delete-orphan". + + + + + 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 + cascade="persist,merge,save-update". + + + + + + Mapear una asociación (ya sea una asociación monovaluada, o una colección) con + cascade="all" marca la asociación como una relación del estilo + padre/hijo donde save/update/delete en el padre resulta + en save/update/delete del hijo o hijos. + + + 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 no es borrado + automáticamente, excepto en el caso de una asociación <one-to-many> + mapeada con cascade="delete-orphan". La semántica precisa de + las operaciones en cascada para una relación padre/hijo es: + + + + + + Si un padre le es pasado a persist(), todos los hijos le son + pasados a persist() + + + + + Si un padre le es pasado a merge(), todos los hijos le son + pasados a merge() + + + + + Si un padre le es pasado a save(), update() o + saveOrUpdate(), todos los hijos le son pasados a saveOrUpdate() + + + + + Si un hijo transitorio o separado se vuelve referenciado por un padre + persistente, le es pasado a saveOrUpdate() + + + + + Si un padre es borrado, todos los hijos le son pasados a delete() + + + + + Si un hijo deja de ser referenciado por un padre persistente, + no ocurre nada especial - la aplicación debe + borrar explícitamente el hijo de ser necesario - a menos que + cascade="delete-orphan", en cuyo caso el hijo + "huérfano" es borrado. + + + + + + + + Usando metadatos + + + 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). + + + Hibernate expone los metadatos vía las interfaces ClassMetadata y + CollectionMetadata y la jerarquía Type. Las instancias + de las interfaces de metadatos pueden obtenerse de SessionFactory. + + + + + + + + diff --git a/documentation/manual/es-ES/src/main/docbook/content/toolset_guide.xml b/documentation/manual/es-ES/src/main/docbook/content/toolset_guide.xml new file mode 100644 index 0000000000..a6efd9a11b --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/content/toolset_guide.xml @@ -0,0 +1,459 @@ + + Guía del Conjunto de Herramientas + + + 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. + + + + Las Herramientas de Hibernate actualmente incluyen plugins para la IDE de + Eclipse así como tareas de Ant para la ingeniería inversa de bases de datos existentes: + + + + + Editor de Mapeo: 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. + + + Consola: 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. + + + Asistentes de Desarrollo: 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. + + + Tareas de Ant: + + + + + + Por favor refiérete al paquete Herramientas de Hibernate y su documentación para + más información. + + + + Sin embargo, el paquete principal de Hibernate viene incluyendo una herramienta integrada + (puede ser usada incluso "dentro" de Hibernate on-the-fly): SchemaExport + también conocido como hbm2ddl. + + + + Generación automática de esquemas + + + 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. + + + + Debes especificar un Dialecto SQL vía la propiedad + hibernate.dialect al usar esta herramienta, ya que el DDL es altamente específico del + vendedor. + + + + First, customize your mapping files to improve the generated schema. + + + + Personalizando el esquema + + + Muchos elementos de mapeo de Hibernate definen un atributo opcional llamado length. + Con este atributo puedes establecer el tamaño de una columna. (O, para tipos de datos + numéricos/decimales, la precisión.) + + + + Algunas etiquetas también aceptan un atributo not-null (para generar una restricción + NOT NULL en columnas de tablas) y y un atributo unique (para generar + restricciones UNIQUE en columnas de tablas). + + + + Algunas etiquetas aceptan un atributo index para especificar el nombre de un índice + para esa columna. Se puede usar un atributo unique-key para agrupar columnas en una + restricción de clave de una sola unidad. Actualmente, el valor especificado del atributo + unique-key no es usado para nombrar la restricción, sólo para + agrupar las columnas en el fichero de mapeo. + + + + Ejemplos: + + + + + + +]]> + + + Alternativamente, estos elementos aceptan tambíen un elemento hijo <column>. + Esto es particularmente útil para tipos multicolumnas: + + + + +]]> + + + + + +]]> + + + El atributo sql-type permite al usuario sobrescribir el mapeo por defecto de + tipo Hibernate a tipo de datos SQL. + + + + El atributo check te permite especificar una comprobación de restricción. + + + + +]]> + + + ... + +]]> + + + + Resumen + + + + + + + Atributo + Valores + Interpretación + + + + + length + number + largo de columna/precisión decimal + + + not-null + true|false + especifica que la columna debe ser no nulable + + + unique + true|false + especifica que la columna debe tener una restricción de unicidad + + + index + index_name + especifica el nombre de un índice (multicolumna) + + + unique-key + unique_key_name + especifica el nombre de una restricción de unicidad multicolumna + + + foreign-key + foreign_key_name + + 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 + inverse="true" no serán considerados por + SchemaExport. + + + + sql-type + column_type + + sobrescribe el tipo de columna por defecto (sólo atributo del elemento + <column>) + + + + check + expresión SQL + + crea una restricción de comprobación SQL en columna o tabla + + + + +
+ + + El elemento <comment> te permite especificar un comentario para el esquema + generado. + + + + Current customers only + ... +]]> + + + + Balance in USD + +]]> + + + Esto resulta en una sentencia comment on table o comment on column + en el DDL generado (donde esté soportado). + + +
+ + + Ejecutando la herramienta + + + La herramienta SchemaExport escribe un guión DDL a la salida estándar y/o + ejecuta las sentencias DDL. + + + + java -cp classpaths_de_hibernate + org.hibernate.tool.hbm2ddl.SchemaExport opciones ficheros_de_mapeo + + + + Opciones de Línea de Comandos de <literal>SchemaExport</literal> + + + + + + Opción + Descripción + + + + + --quiet + no enviar a salida estándar el guión + + + --drop + sólo desechar las tablas + + + --text + no exportar a la base de datos + + + --output=my_schema.ddl + enviar la salida del guión ddl a un fichero + + + --config=hibernate.cfg.xml + lee la configuración de Hibernate de un fichero XML + + + --properties=hibernate.properties + lee las propiedades de base de datos de un fichero + + + --format + formatea agradablemente el SQL generado en el guión + + + --delimiter=x + establece un delimitador de fin de línea para el guión + + + +
+ + + Puedes incluso encajar SchemaExport en tu aplicación: + + + + +
+ + + Propiedades + + + Las propiedades de base de datos pueden especificarse + + + + + como propiedades de sistema con -D<property> + + + en hibernate.properties + + + en un fichero de propiedades mencionado con --properties + + + + + Las propiedades necesarias son: + + + + Propiedades de Conexión de SchemaExport + + + + + + Nombre de Propiedad + Descripción + + + + + hibernate.connection.driver_class + clase del driver jdbc + + + hibernate.connection.url + url de jdbc + + + hibernate.connection.username + usuario de base de datos + + + hibernate.connection.password + contraseña de usuario + + + hibernate.dialect + dialecto + + + +
+ +
+ + + Usando Ant + + + Puedes llamar a SchemaExport desde tu guión de construcción de Ant: + + + + + + + + + + +]]> + + + + + Actualizaciones incrementales de esquema + + + La herramienta SchemaUpdate actualizará un esquema existente con cambios + "incrementales". Nota que SchemaUpdate depende fuertemente de la API de metadatos + de JDBC, de modo que no funcionará con todos los drivers JDBC. + + + + java -cp classpaths_de_hibernate + org.hibernate.tool.hbm2ddl.SchemaUpdate opciones ficheros_de_mapeo + + + + Opciones de Línea de Comandos de <literal>SchemaUpdate</literal> + + + + + + Opción + Descripción + + + + + --quiet + no enviar a salida estándar el guión + + + --properties=hibernate.properties + lee las propiedades de base de datos de un fichero + + + +
+ + + Puedes encajar SchemaUpdate en tu aplicación: + + + + +
+ + + Usando Ant para actualizaciones incrementales de esquema + + + Puedes llamar a SchemaUpdate desde el guión de Ant: + + + + + + + + + + +]]> + + + +
+ +
+ diff --git a/documentation/manual/es-ES/src/main/docbook/content/transactions.xml b/documentation/manual/es-ES/src/main/docbook/content/transactions.xml new file mode 100644 index 0000000000..c3e1e62036 --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/content/transactions.xml @@ -0,0 +1,925 @@ + + Transacciones y Concurrencia + + + 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. + + + + Sin embargo, además del versionado automático, Hibernate ofrece una API (menor) para + bloqueo pesimista de filas, usando la sintáxis SELECT FOR UPDATE. + Esta API se discute más adelante en este capítulo: + + + + Comenzamos la discusión del control de concurrencia en Hibernate con la granularidad + de Configuration, SessionFactory, y + Session, así como la base de datos y las transacciones de aplicación + largas. + + + + Ámbitos de sesión y de transacción + + + Una SessionFactory 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 Configuration. + + + + Una Session 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 Session no obtendrá una Connection + JDBC (o un Datasource) a menos que sea necesario, de modo que puedas + abrir y cerrar seguramente una Session 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 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. + + + + ¿Qué es el ámbito de una unidad de trabajo? ¿Puede una sola Session 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 Session y cómo demarcas los + límites de la transacción de base de datos? + + + + Unidad de trabajo + + + Primero, no uses el antipatrón sesión-por-operación, esto es, + ¡no abras y cierres una Session 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.) + + + + El patrón más común en una aplicación mutiusuario cliente/servidor es + sesión-por-petición. 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 Session 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 Session. + La relación entre las dos es uno-a-uno y este modelo es a la medida perfecta de muchas + aplicaciones. + + + + El desafío yace en la implementación: no sólo tienen que comenzarse y terminarse correctamente + la Session 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 ServletFilter). Recomendamos ligar la + Session a la hebra que atiende la petición, usando una variable + ThreadLocal. 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 ThreadLocal. Los patrones de implementación para esto son + conocidos como Sesión Local de Hebra (ThreadLocal Session) y + Sesión Abierta en Vista (Open Session in View). Puedes extender fácilmente + la clase de ayuda HibernateUtil 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. + + + + + + Transacciones de aplicación + + + 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: + + + + + + Se abre la primera pantalla de un diálogo, los datos vistos por el usuario han sido + cargados en una Session y transacción de base de datos particular. + El usuario es libre de modificar los objetos. + + + + + 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. + + + + + + Llamamos a esto unidad de trabajo, desde el punto de vista del usuario, una larga + transacción de aplicación ejecutándose. Hay muchas formas en + que puedes implementar esto en tu aplicación. + + + + Una primera implementación ingenua podría mantener abierta la Session + 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. + + + + 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: + + + + + + Versionado Automático - 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. + + + + + Objetos Separados - Si decides usar el ya discutido patrón + de sesión-por-petición, 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 sesión-por-petición-con-objetos-separados. Se usa + versionado automático para aislar las modificaciones concurrentes. + + + + + Sesión Larga - La Session 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 sesión-por-transacción-de-aplicación + y hace la re-unión innecesaria. Para aislar las modificaciones concurrentes se usa el + versionado automático. + + + + + + Tanto sesión-por-petición-con-objetos-separados como + sesión-por-transacción-de-aplicación, ambas tienen + ventajas y desventajas, las discutimos más adelante en este capítulo en el contexto + del control optimista de concurrencia. + + + + + + Considerando la identidad del objeto + + + Una aplicación puede acceder concurrentemente a el mismo estado persistente en dos + Sessions diferentes. Sin embargo, una instancia de una clase + persistente nunca se comparte entre dos instancias de Session. + Por lo tanto existen dos nociones diferentes de identidad: + + + + + Identidad de Base de Datos + + + foo.getId().equals( bar.getId() ) + + + + + Identidad JVM + + + foo==bar + + + + + + + Entonces para objetos unidos a una Session en particular + (es decir en el ámbito de una Session) 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. + + + + 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 + Session. Dentro de una Session la aplicación puede usar + con seguridad == para comparar objetos. + + + + Sin embargo, una aplicación que usa == fuera de una Session, + podría ver resultados inesperados. Esto podría ocurrir incluso en sitios algo inesperados, + por ejemplo, si pones dos instancias separadas dentro del mismo Set. + 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 equals() y + hashCode() 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 + Set, cambiar el código hash rompe el contrato del Set. + 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 + Set. 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. + + + + + + Temas comunes + + + Nunca uses los antipatrones sesión-por-sesión-de-usuario o + sesión-por-aplicación (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: + + + + + + Una Session 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 Session + fuese compartida. Si guardas tu Session de Hibernate en tu + HttpSession (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 Session en dos hebras ejecutándose + concurrentemente. + + + + + Una excepción lanzada por Hibernate significa que tienes que deshacer (rollback) tu + transacción de base de datos y cerrar la Session inmediatamente + (discutido en más detalle luego). Si tu Session 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. + + + + + La Session 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 + clear() y evict() para gestionar el caché de la + Session, pero probalemente debas considerar un procedimiento almacenado + si necesitas operaciones de datos masivas. Se muestran algunas soluciones en + . Mantener una Session abierta por la duración + de una sesión de usuario significa también una alta probabilidad de datos añejos. + + + + + + + + + + Demarcación de la transacción de base de datos + + + 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. + + + + 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 Session es hecho automáticamente. + + + + Sin embargo, frecuentemente es deseable mantener portable tu capa de persistencia. Hibernate ofrece + una API de envoltura llamada Transaction 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. + + + + Usualmente, finalizar una Session implica cuatro fases distintas: + + + + + + limpiar (flush) la sesión + + + + + comprometer la transacción + + + + + cerrar la sesión + + + + + manejar excepciones + + + + + + 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. + + + + + Entorno no manejado + + + 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í: + + + + + + No tienes que limpiar con flush() la Session explícitamente - + la llamada a commit() automáticamente dispara la sincronización. + + + + Una llamada a close() marca el fin de una sesión. La principal implicación + de close() es que la conexión JDBC será abandonada por la sesión. + + + + Este código Java es portable y se ejecuta tanto en entornos no manejados como en entornos JTA. + + + + 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 RuntimeException (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. + + + + Nota que debes seleccionar org.hibernate.transaction.JDBCTransactionFactory + (que es el por defecto). + + + + + + Usando JTA + + + 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. + + + + 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 Transaction. + De modo que, el código de gestión de la transacción es idéntico al de un entorno no manejado. + + + + + + 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 Session + por ti mismo, solamente establece hibernate.transaction.flush_before_completion a + true, hibernate.connection.release_mode a + after_statement o auto y + hibernate.transaction.auto_close_session a true. Hibernate + limpiará y cerrará entonces automáticamente la Session 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 RuntimeException 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. Esto significa que, en CMT, no necesitas usar en absoluto la API de + Transaction de Hibernate. + + + + Nota que debes elegir org.hibernate.transaction.JTATransactionFactory en un + bean de sesión BMT, y org.hibernate.transaction.CMTTransactionFactory en un + bean de sesión CMT, cuando configures la fábrica de transacciones de Hibernate. Recuerda además + establecer org.hibernate.transaction.manager_lookup_class. + + + + 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 ThreadLocal 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 Session + por alrededor, la SessionFactory provee el método + getCurrentSession(), 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: + + + + + + En otras palabras, todo lo que tienes que hacer en un entorno manejado, es llamar a + SessionFactory.getCurrentSession(), 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. + + + + Existe una advertencia al uso del modo de liberación de conexión after_statement. + Debido a una limitación tonta de la especificación de JTA, no es posible para Hibernate + limpiar automáticamente ningún ScrollableResults no cerrado ni + instancias de Iterator devueltas por scroll() o + iterate(). Debes liberar el cursor de base de datos + subyacente llamando a ScrollableResults.close() o + Hibernate.close(Iterator) explícitamente desde un bloque finally. + (Por supuesto, la mayoría de las aplicaciones pueden evitarlo fácilmente no usando en absoluto ningún + scroll() o iterate() desde el código CMT.) + + + + + + Manejo de excepciones + + + Si la Session lanza una excepción (incluyendo cualquier + SQLException), debes inmediatamente deshacer (rollback) la + transacción de base de datos, llamar a Session.close() y + descartar la instancia de Session. Ciertos métodos de + Session no dejarán la sesión en un + estado consistente. Ninguna excepción lanzada por Hibernate puede ser tratada + como recuperable. Asegúrate que la Session sea cerrada llamando + a close() en un bloque finally. + + + + La HibernateException, 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 HibernateException. Una vez más, no son recuperables y debe + tomarse una acción apropiada. + + + + Hibernate envuelve SQLExceptions lanzadas mientras se interactúa con la base + de datos en una JDBCException. De hecho, Hibernate intentará convertir la excepción + en una subclase de JDBCException más significativa. La SQLException + está siempre disponible vía JDBCException.getCause(). Hibernate convierte la + SQLException en una subclase de JDBCException apropiada usando + el SQLExceptionConverter adjunto a la SessionFactory. Por defecto, + el SQLExceptionConverter está definido para el dialecto configurado; sin embargo, + es también posible enchufar una implementación personalizada (ver los javadocs de la clase + SQLExceptionConverterFactory para los detalles). Los subtipos estándar de + JDBCException son: + + + + + + JDBCConnectionException - indica un error con la comunicación JDBC subyacente. + + + + + SQLGrammarException - indica un problema de gramática o sintáxis con el + SQL publicado. + + + + + ConstraintViolationException - indica alguna forma de violación de restricción + de integridad. + + + + + LockAcquisitionException - indica un error adquiriendo un nivel de bloqueo + necesario para realizar una operación solicitada. + + + + + GenericJDBCException - una excepción genérica que no cayó en ninguna de las + otras categorías. + + + + + + + + + + + Control optimista de concurrencia + + + 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. + + + + Chequeo de versiones de aplicación + + + En una implementación sin mucha ayuda de Hibernate, cada interacción con la base de datos ocurre en una + nueva Session 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. + + + + + + La propiedad version se mapea usando <version>, + e Hibernate la incrementará automáticamente durante la limpieza si la entidad está sucia. + + + + 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, el último compromiso (commit) gana 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. + + + + 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 Session larga o de instancias separadas. + + + + + + Sesión larga y versionado automático + + + Una sola instancia de Session 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). + + + + La Session 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. + + + + + + El objeto foo todavía conoce en qué Session fue cargado. + Session.reconnect() obtiene una nueva conexión (o puedes proveer una) y + reasume la sesión. El método Session.disconnect() 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 Session.lock() con LockMode.READ sobre + cualquier objeto que pudiese haber sido actualizado por otra transacción. No necesitas bloquear + ningún dato que sí estés actualizando. + + + + Si las llamadas explícitas a disconnect() y reconnect() + son muy onerosas, puedes usar en cambio hibernate.connection.release_mode. + + + + Este patrón es problemático si la Session es demasiado grande para ser almacenada + durante el tiempo de pensar del usuario, por ejemplo, una HttpSession debe + mantenerse tan pequeña como sea posible. Ya que la Session 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 Session tendrá pronto también datos añejos. + + + + Nota también que debes mantener la Session desconectada próxima a la capa + de persistencia. En otras palabras, usa una sesión de EJB con estado para tener la + Session y no transferirla a la capa web para almacenarla en la + HttpSession (ni incluso serializarla a una capa separada). + + + + + + Objetos separados y versionado automático + + + Cada interacción con el almacén persistente ocurre en una nueva Session. + 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 + Session y luego las readjunta usando Session.update(), + Session.saveOrUpdate(), o Session.merge(). + + + + + + De nuevo, Hibernate chequeará las versiones de instancia durante la limpieza (flush), + lanzando una excepción si ocurrieron actualizaciones en conflicto. + + + + Puedes también llamar a lock() en vez de update() + y usar LockMode.READ (realizando un chequeo de versión, puenteando + todos los cachés) si estás seguro que el objeto no ha sido modificado. + + + + + + Personalizando el versionado automático + + + Puedes deshabilitar el incremento de versión automático de Hibernate para propiedades en particular + y colecciones estableciendo el atributo de mapeo optimistic-lock a + false. Hibernate entonces no incrementará ya más las versiones si la propiedad está + sucia. + + + + 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 + optimistic-lock="all" en el mapeo de <class>. + Nota que esto conceptualmente funciona solamente si Hibernate puede comparar el estado viejo y nuevo, + es decir, si usas una sola Session larga y no + sesión-por-petición-con-instancias-separadas. + + + + A veces las modificaciones concurrentes pueden permitirse, en cuanto los cambios que hayan sido + hechos no se traslapen. Si estableces optimistic-lock="dirty" al mapear la + <class>, Hibernate sólo comparará los campos sucios durante la limpieza. + + + + En ambos casos, con columnas de versión/timestamp dedicadas o con comparación de campos + completa/sucios, Hibernate usa una sola sentencia UPDATE + (con una cláusula WHERE 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) + on update en la base de datos incluso cuando no se haya hecho ningún cambio + a las instancias separadas. Puedes personalizar este comportamiento estableciendo + select-before-update="true" en el mapeo de <class>, + forzando a Hibernate a SELECT la instancia para asegurar que las actualizaciones + realmente ocurran, antes de actualizar la fila. + + + + + + + + Bloqueo pesimista + + + 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. + + + + ¡Hibernate siempre usará el mecanismo de bloqueo de la base de datos, nunca bloqueo + de objetos en memoria! + + + + La clase LockMode define los diferentes niveles de bloqueo que pueden ser adquiridos + por Hibernate. Un bloqueo se obtiene por los siguientes mecanismos: + + + + + + LockMode.WRITE se adquiere automáticamente cuando Hibernate actualiza o + inserta una fila. + + + + + LockMode.UPGRADE puede ser adquirido bajo petición explícita del usuario + usando SELECT ... FOR UPDATE en base de datos que soporten esa sintáxis. + + + + + LockMode.UPGRADE_NOWAIT puede ser adquirido bajo petición explícita del usuario + usando un SELECT ... FOR UPDATE NOWAIT bajo Oracle. + + + + + LockMode.READ 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. + + + + + LockMode.NONE representa la ausencia de un bloqueo. Todos los objetos se pasan + a este modo de bloqueo al final de una Transaction. Los objetos asociados con una + sesión vía una llamada a update() o saveOrUpdate() también + comienzan en este modo de bloqueo. + + + + + + La "petición explícita del usuario" se expresa en una de las siguientes formas: + + + + + + Una llamada a Session.load(), especificando un LockMode. + + + + + Una llamada a Session.lock(). + + + + + Una llamada a Query.setLockMode(). + + + + + + Si se llama a Session.load() con UPGRADE o + UPGRADE_NOWAIT, y el objeto pedido no ha sido aún cargado por la sesión, el objeto es + cargado usando SELECT ... FOR UPDATE. Si se llama a load() para + un objeto que ya esté cargado con un bloqueo menos restrictivo que el pedido, Hibernate llama a + lock() para ese objeto. + + + + Session.lock() realiza un chequeo de número de versión si el modo de bloqueo especificado + es READ, UPGRADE o UPGRADE_NOWAIT. (En el caso de + UPGRADE o UPGRADE_NOWAIT, se usa + SELECT ... FOR UPDATE.) + + + + 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. + + + + + + diff --git a/documentation/manual/es-ES/src/main/docbook/content/tutorial.xml b/documentation/manual/es-ES/src/main/docbook/content/tutorial.xml new file mode 100644 index 0000000000..99dfb74997 --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/content/tutorial.xml @@ -0,0 +1,1270 @@ + + Introducción a Hibernate + + + Prefacio + + + 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. + + + + 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. + + + + + + Parte 1 - La primera Aplicación Hibernate + + + 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. + + + + 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. + + + + 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 /lib dentro del directorio + /lib de nuestro nuevo directorio de desarrollo de trabajo. + Debe asemejarse a esto: + + + + + + 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 + README.txt en el directorio lib/ 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). + + + + Por siguiente, creamos una clase que represente el evento que queremos + almacenar en base de datos. + + + + La primera clase + + + Nuestra primera clase persistente es un JavaBean simple con algunas propiedades: + + + + + + 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. + + + + La propiedad id 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. + + + + 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. + + + + Coloca este fichero de código Java en un directorio llamado src + en la carpeta de desarrollo. El directorio ahora debe verse como esto: + + + ++src + Event.java]]> + + + En el próximo paso, le decimos a Hibernate sobre esta clase persistente. + + + + + + El fichero de mapeo + + + 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. + + + + La estructura básica de un fichero de mapeo se parece a esto: + + + + + + +[...] +]]> + + + 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 hibernate3.jar + así como también en el directorio src/ de la + distribución de Hibernate. + + + + Omitiremos la declaración de DTD en futuros ejemplos para acortar + el código. Por supuesto, no es opcional. + + + + Entre las dos etiquetas hibernate-mapping, incluye + un elemento class. 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: + + + + + + + + +]]> + + + Hasta ahora dijimos a Hibernate cómo persistir y cargar el objeto + de clase Event a la tabla EVENTS, + 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: + + + + + + + + + + +]]> + + + El elemento id el la declaración de la propiedad + identificadora, name="id" 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 EVENTS usamos para esta clave primaria. + El elemento anidado generator especifica la estrategia de + generación de identificadores, en este caso usamos increment, + 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). + + + + 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: + + + + + + + + + + + + +]]> + + + Al igual que con el elemento id, el atributo name + del elemento property dice a Hibernate cáles métodos + getter y setter usar. + + + + ¿Por qué el mapeo de la propiedad date + incluye el atributo column, pero el de la de + title no? Sin el atributo column + Hibernate usa por defecto el nombre de propiedad como nombre de columna. + Esto funciona bien para title. Sin embargo, + However, date es una palabra reservada en la + mayoría de las bases de datos, así que mejor la mapeamos + a un nombre diferente. + + + + La próxima cosa interesante es que el mapeo de title + carece de un atributo type. 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í + Tipos de mapeo de Hibernate, 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 + type 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 + date. Hibernate no puede saber is la propiedad mapeará + a una columna date, timestamp o + time. Declaramos que queremos preservar la información + completa de fecha y hora mapeando la propiedad con un timestamp. + + + + Este fichero de mapeo debe ser salvado como Event.hbm.xml, + justo en el directorio próximo al fichero de código fuente de + la clase Java Event. El nombrado de los ficheros de mapeo + puede ser arbitrario, sin embargo, el sufijo hbm.xml se ha + vuelto una convención el la comunidad de desarrolladores de Hibernate. + La estructura de directorio debe ahora verse como esto: + + + ++src + Event.java + Event.hbm.xml]]> + + + Continuamos con la configuración principal de Hibernate. + + + + + + Configuración de Hibernate + + + 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 hsqldb.jar. + Coloca este fichero en el directorio lib/ de la carpeta de desarrollo. + + + + Crea un directorio llamado data en la raíz del directorio de + desarrollo. Allí es donde HSQL DB almacenará sus ficheros de datos. + + + + 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 la configuración de Hibernate, podemos usar un fichero + hibernate.properties simple, un fichero hibernate.cfg.xml + 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: + + + + + + + + + + + org.hsqldb.jdbcDriver + jdbc:hsqldb:data/tutorial + sa + + + + 1 + + + org.hibernate.dialect.HSQLDialect + + + true + + + create + + + + + +]]> + + + Observa que esta configuración XML usa un DTD diferente. + Configuramos la SessionFactory de Hibernate, una + fábrica global responsable de una base de datos en particular. + Si tienes varias bases de datos, usa varias configuraciones + <session-factory> , usualmente en varios + ficheros de configuración (para un arranque más fácil). + + + + Los primeros cuatro elementos property contienen la configuración + necesaria para la conexión JDBC. El elemento de dialecto property + especifica la variante de SQL en particular que genera Hibernate. La opción + hbm2ddl.auto 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 SchemaExport. Finalmente, agregamos el(los) fichero(s) de mapeo + para clases persistentes. + + + + 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 hibernate.cfg.xml en la raíz del classpath + al arrancar. + + + + + + Construyendo con Ant + + + Construiremos ahora el tutorial con Ant. Necesitarás tener Ant instalado. + Obténlo de Página + de descarga de Ant. No se cubrirá aquí cómo instalar Ant. + Por favor refiérete al + Manual de Ant. Después que hayas instalado Ant, podemos comenzar a + crear el buildfile. Será llamado build.xml y colocado + directamente en el directorio de desarrollo. + + + + Reparar Ant + + 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 ANT_HOME/lib o quita el trozo de plugin + ANT_HOME/lib/ant-junit.jar. + + + + + Un fichero de construcción básico se ve como esto: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]]> + + + Esto dirá a Ant que agregue todos los ficheros en el directorio lib que terminen con + .jar 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: + + + 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 ]]> + + + + + Arranque y ayudantes + + + Es momento de cargar y almacenar algunos objetos Event, + 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 SessionFactory global + y almacenarlo en algún sitio de fácil acceso en el código + de aplicación. Una SessionFactory puede abrir nuevas + Session's. Una Session representa un unidad + de trabajo mono-hebra. La SessionFactory es un objeto global + seguro entre hebras, instanciado una sola vez. + + + + Crearemos una clase de ayuda HibernateUtil que cuide del + arranque y haga conveniente el manejo de Session. + El así llamado patrón Sesión de Hebra Local + (ThreadLocal Session) es útil aquí; mantenemos la unidad + de trabajo actual asociada a la hebra actual. Echemos una mirada a la implementación: + + + + + + Esta clase no ólo produce la SessionFactory global en + su inicializador static (llamado sólo una vez por la JVM al cargar la clase), + sino que también tiene una variable ThreadLocal para + tener la Session para la hebra actual. No importa cuándo + llames a HibernateUtil.currentSession(), siempre devolverá + la misma unidad de trabajo de Hibernate en la misma hebra. Una llamada a + HibernateUtil.closeSession() termina la unidad de trabajo actualmente + asociada a la hebra. + + + + Asegúrate de entender el concepto Java de una variable local a una hebra antes + de usar esta ayuda. Una clase HibernateUtil más potente puede + encontrarse en CaveatEmptor, 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 Session + será automáticamente ligada a la transacción JTA actual, y puedes + buscar la SessionFactory a través de JNDI. Si usas JBoss AS, + Hibernate puede ser desplegado como un servicio de sistema manejado y automáticamente + ligará la SessionFactory a un nombre JNDI. + + + + Coloca HibernateUtil.java en el directorio de fuentes de desarrollo, + junto a Event.java: + + + ++src + Event.java + Event.hbm.xml + HibernateUtil.java + hibernate.cfg.xml ++data +build.xml]]> + + + 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 log4j.properties de la distribución de Hibernate + (está en el directorio etc/) a tu directorio src, + junto a hibernate.cfg.xml. 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. + + + + La infraestructura del tutorial está completa, y estamos listos para hacer + algún trabajo real con Hibernate. + + + + + + Cargando y almacenando objetos + + + Finalmente, podemos usar Hibernate para cargar y almacenar objetos. + Escribimos una clase EventManager con un método + main(): + + + + + + Leemos algunos argumentos de la línea de comandos, y si el primer + argumento es "store", creamos y almacenamos un nuevo Event: + + + + + + Creamos un nuevo objeto Event, y se lo damos a Hibernate. + Hibernate cuida ahora del SQL y ejecuta INSERTs en la base + de datos. Echemos una mirada al código de manejo de Session + y Transaction antes de ejecutar esto. + + + + Una Session es una sola unidad de trabajo. Podría sorprenderte + que tengamos una API adicional, Transaction. 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 Transacción de + Aplicación, 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 Session y una Transaction. + + + + ¿Qué es lo que hacen Transaction.begin() y commit()? + ¿Dónde está el rollback en caso que algo vaya mal? La API de Transaction + 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 + session.connection.commit()), ligarías el código a un entorno + de despliegue particular, en este JDBC directo no manejado. Estableciendo la fábrica + de Transaction en tu configuración de Hibernate puedes desplegar + tu capa de persistencia en cualquier sitio. Echa una mirada al + 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 ejecutar la primera rutina tenemos que agregar un objetivo llamable al fichero + de construcción de Ant: + + + + + + + +]]> + + + El valor del argumento action es establecido por línea de + comandos al llamar al objetivo: + + + ant run -Daction=store]]> + + + 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: + + + + + + Esta es la INSERT 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 + log4j.properties. + + + + Ahora quisiéramos listar acontecimientos almacenados también, + así que agregamos una opción al método principal: + + + + + + Agregamos también un nuevo método listEvents(): + + + + + + Lo que hacemos aquí es usar una consulta HQL (Lenguaje de Consulta de Hibernate + o Hibernate Query Language) para cargar todos los objetos Event + existentes de la base de datos. Hibernate generará el SQL apropiado, lo enviará + a la base de datosy poblará los objetos Event con datos. + Puedes, por supuesto, crear consultas más complejas con HQL. + + + + Si ahora llamas a Ant con -Daction=list, 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 hbm2ddl.auto + 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 store + unas cuantas veces. La generación y exportación de esquema es útil + mayormente en testeo unitario. + + + + + + + + Part 2 - Mapeando asociaciones + + + 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. + + + + Mapeando la clase Person + + + El primer corte de la clase Person es simple: + + + + + + Crea un fichero de mapeo llamado Person.hbm.xml: + + + + + + + + + + + + + +]]> + + + Finalmente, agrega el nuevo mapeo a la configuración de Hibernate: + + + + +]]> + + + 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. + + + + + + Una asociación unidireccional basada en Set + + + Agregaremos una colección de eventos a la clase Person. + De esta forma podemos navegar facilmente a los eventos de una persona en particular, + sin ejecutar una consulta explícita, llamando a aPerson.getEvents(). + Usamos una colección Java, un Set, porque la colección no + contendrá elementos duplicados y el ordenamiento no nos es relevante. + + + + Hasta ahora hemos diseñado asociaciones unidireccionales multivaluadas, implementadas con un + Set. Escribamos el código para esto en las clases Java y luego lo + mapeemos: + + + + + + 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 + Event, si queremos ser capaces de navegarlos bidireccionalmente; + por ejemplo, anEvent.getParticipants(). 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 muchos-a-muchos. Por lo tanto, usamos un mapeo + many-to-many de Hibernate: + + + + + + + + + + + + + + + +]]> + + + Hibernate soporta todo tipo de mapeos de colección, siendo el más común + un <set>. Para una asociación muchos-a-muchos (o relación + de entidad n:m), 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 + table del elemento set. El nombre de la columna identificadora + en la asociación, para el lado de la persona, se define con el elemento + <key>. El nombre de columna para el lado del evento se define con el atributo + column del <many-to-many>. 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). + + + + El esquema de base de datos para este mapeo es, por lo tanto: + + + | *EVENT_ID | | | + | EVENT_DATE | | *PERSON_ID | <--> | *PERSON_ID | + | TITLE | |__________________| | AGE | + |_____________| | FIRSTNAME | + | LASTNAME | + |_____________| + ]]> + + + + + Trabajando la asociación + + + Traigamos alguna gente y eventos juntos en un nuevo método en + EventManager: + + + + + + Después de cargar una Person y un Event, simplemente + modifica la colección usando sus métodos normales. Como puedes ver, no hay una llamada + explícita a update() o save(). Hibernate detecta + automáticamente que la colección ha sido modificada y necesita ser salvada. Esto + es llamado chequeo sucio automótico (automatic dirty checking), y + también puedes intentarlo modificando el nombre de la propiedad de fecha de cualquiera de tus + objetos. Mientras estén en estado persistente, esto es, ligados a una + Session 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 limpieza (flushing). + + + + Podrías, por supuesto, cargar persona y evento en unidades de trabajo diferentes. O + modificas un objeto fuera de una Session, cuando no está en estado + persistente (si antes era persistente llamamos a este estado separado (detached) + ). En código (no muy realista), esto se vería como sigue: + + + + + + La llamada a update 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. + + + + 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 + EventManager y llámala desde la línea de comandos. + Si necesitas los identificadores de una persona o evento, el método + save() los devuelve. + + + + 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 int + o un String. Llamamos a estas clases tipos de valor (value types), + y sus instancias dependen 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 firstname, 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, Address o + MonetaryAmount. + + + + 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. + + + + + + Colección de valores + + + Agregamos una colección de objetos tipificados en valor a la entidad Person. + Queremos almacenar direcciones de email, de modo que el tipo que usamos es String, + y la colección es nuevamente un Set: + + + + + El mapeo de este Set: + + + + + +]]> + + + La diferencia comparada con el mapeo anterior es la parte element, que le dice + a Hibernate que la colección no contiene referencias a otra entidad, sino una colección + de elementos de tipo String (el nombre en minúsculas te dice que es un + tipo/conversor de mapeo de Hibernate). Una vez más, el atributo table del + elemento set determina el nombre de la tabla para la colección. El elemento + key define el nombre de la columna clave foránea en la tabla de colección. + El atributo column en el elemento element define el nombre de + columna donde realmente serán almacenados los valores String. + + + + Echa una mirada al esquema actualizado: + + + | *EVENT_ID | | | |___________________| + | EVENT_DATE | | *PERSON_ID | <--> | *PERSON_ID | <--> | *PERSON_ID | + | TITLE | |__________________| | AGE | | *EMAIL_ADDR | + |_____________| | FIRSTNAME | |___________________| + | LASTNAME | + |_____________| + ]]> + + + 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. + + + + 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. + + + + + + Asociaciones bidireccionales + + + 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. + + + + Primero agrega una colección de participantes a la clase de eventos + Event: + + + + + + Ahora mapea este lado de la asociación también, en + Event.hbm.xml. + + + + + +]]> + + + Como ves, estos son mapeos normales de set en ambos documentos de + mapeo. Nota que los nombres de columnas en key y + many-to-many fueron permutados en ambos documentos de mapeo. Aquí la + adición más importante es el atributo inverse="true" en el + elemento set del mapeo de colección de Event. + + + + Lo que esto significa es que Hibernate debe tomar el otro lado - la clase Person - + 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. + + + + + + Trabajando enlaces bidireccionales + + + Primero, ten en mente que Hhibernate no afecta la semántica normal de Java. ¿Cómo + hemos creado un enlace entre una Person y un Event en el + ejemplo unidireccional? Hemos agregado una instancia de Event a la colección + de referencias de eventos de una instancia de Person. De modo que, obviamente, + si queremos que este enlace funcione bidireccionalmente, tenemos que hacer lo mismo del otro lado, + agregando una referencia a Person a la colección en un Event. + Este "establecer el enlace a ambos lados" es absolutamente necesario y nunca debes olvidar hacerlo. + + + + Muchos desarrolladores programan a la defensiva y crean métodos de + manejo de un enlace para establecer correctamente ambos lados, por ejemplo + en Person: + + + + + + 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. + + + + Y ¿qué del atributo de mapeo inverse? 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 INSERT y UPDATE 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 inverse le dice a Hibernate que basicamente + lo ignore, que lo considere un espejo 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 inverse. 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. + + + + + + + Summary + + + Este tutorial cubrió los fundamentos de escribir una simple aplicación independiente + de Hibernate. + + + + 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 (), + rendimiento de recuperación (), o el uso de la API + () y las funcionalidades de consulta (). + + + + No olvides chequear el sitio web de Hibernate por más (especializados) tutoriales. + + + + + \ No newline at end of file diff --git a/documentation/manual/es-ES/src/main/docbook/content/xml.xml b/documentation/manual/es-ES/src/main/docbook/content/xml.xml new file mode 100644 index 0000000000..b3ade22d44 --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/content/xml.xml @@ -0,0 +1,282 @@ + + Mapeo XML + + + Nota que esta es una funcionalidad experimental en Hibernate 3.0 y está + bajo un desarrollo extremadamente activo. + + + + Trabajando con datos XML + + + 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. + + + + 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: persist(), saveOrUpdate(), merge(), + delete(), replicate() (la fusión no está aún soportada). + + + + 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. + + + + 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. + + + + Especificando los mapeos de XML y de clase juntos + + + He aquí un ejemplo de mapear un POJO y XML simultáneamente: + + + + + + + + + + + ... + +]]> + + + + Especificando sólo un mapeo XML + + + He aquí un ejemplo donde no hay ninguna clase POJO: + + + + + + + + + + + ... + +]]> + + + Este mapeo te permite acceder a los datos como un árbol dom4j, o como un grafo de pares nombre/valor de + propiedad (Maps de Java). Los nombres de propiedades son construcciones puramente + lógicas a las que se puede hacer referencia en consultas HQL. + + + + + + + + Mapeo de metadatos XML + + + Muchos elementos de mapeo de Hibernate aceptan el atributo node. 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 node debe ser uno de los siguientes: + + + + + "element-name" - mapea al elemento XML mencionado + + + "@attribute-name" - mapea al atributo XML mencionado + + + "." - mapea al elemento padre + + + + "element-name/@attribute-name" - + mapea al atributo mencionado del elemento mencionado + + + + + + Para las colecciones y asociaciones monovaluadas, existe un atributo adicional embed-xml. + Si embed-xml="true", 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 embed-xml="false", sólo el valor identificador + referenciado aparecerá en el XML para asociaciones de punto único y para las colecciones simplemente + no aparecerá en absoluto. + + + + ¡Debes ser cuidadoso de no dejar embed-xml="true" para demasiadas asociaciones, + ya que XML no trata bien la circularidad! + + + + + + + + + + + + + + + + + + + ... + +]]> + + + en este caso, hemos decidido embeber la colección de ids de cuenta, pero no los datos reales de cuenta. + La siguiente consulta HQL: + + + + + + devolvería conjuntos de datos como estos: + + + + 987632567 + 985612323 + + Gavin + A + King + + ... +]]> + + + Si estableces embed-xml="true" en el mapeo <one-to-many>, los datos + podrían verse así: + + + + + + 100.29 + + + + -2370.34 + + + Gavin + A + King + + ... +]]> + + + + + + Manipulando datos XML + + + Vamos a releer y actualizar documentos XML en la aplicación. Hacemos esto obteniendo una sesión dom4j: + + + + + + + + Es extremadamente útil combinar esta funcionalidad con la operación replicate() + de Hibernate para implementar la importación/exportación de datos basada en XML. + + + + + + diff --git a/documentation/manual/es-ES/src/main/docbook/images/AuthorWork.png b/documentation/manual/es-ES/src/main/docbook/images/AuthorWork.png new file mode 100644 index 0000000000000000000000000000000000000000..ef4ab7227ae9e9a7b647f8bef39b8f76abc7ba64 GIT binary patch literal 6000 zcmcgwc~}$KvS$zbs=xq(8zQobBC^DY2UM(rYPfJ;?f-8F1Ea7dFM=O1y6#fG z1O*9nT(+2`DP6CvTp{D4h-U+yuZTe}b3~(Ulybg7+(hrf821n6UIqxMZ0y@^+3$my z0~oM4$XP6w2SYo$$v?5KRj9=@~3NG&2PvIo)#o%ljFqx~H!2`%fP8FQk9ozz}2rnsvzDF&^fJHs9jQ0C| zMAIrfS_(%6+SpRDWs!@NT_L;>CvW!)HZ?NBZpo{n@|10&piZ7K1%~73yHd zN17sARHfOEics=*V|k(qm-N=qN^ww-SjQ6YgRISGi5I~j(049+U6p80)AHVo`5TYR z?Ji!(rPVM1N}~avi25u7xarJl=+cI4kE=A1t^V7Pu+j4y3@v@4Rq1K?cQkbdli!67 z$$lOAtrG*9kG~AoKE0*&SmN_a#F~wDWDx{^9Psh%&xF>v!>!{;d!c@`%Uuiy=5?n1 zmXY%0O3jv4%tY4Pdxk$^NxLBiTK+DQ`c37>dsgnl-*2uhP5gsXttO@raK-Lrg>YbFQdyFiZL7 zp-{tqG?53s#+2S#aeP02k`<%AzNP(6i|5MuESa2fWYx0g8%mGW!ncN6Pq}x0w zsxRvi(&l&y*#RnTFv>?6Wa8)>PQalZorhxKA%j@VUhJ@biA>~@GFeKdF`~dae82XA z!FI~f9@*freLoqBg&q?EaS|F>20n@v-pds*fqbxt7VD9>B{^jSH2 zki|UOng`(ylZTi$o2M|Jv_QRhwzCofo2LUC+xCME%Sic3On_+dfhfu&q%#LWPlv>x zja6QrCdQ4@a0%IC9#i;5@Jnf4jhXx+<97L3s;>k)tb^w^u$LuSZX5K+Slyu24vJEM zS4z0~c9>5w*8)Hv3HZZj#c17}&2LE*Ud~oH{4-r?hV73PJ6F0czT5eH$&?oQB-iI4 zWU{q>yT!1t%#AhmcsO5SB;xXBSm}|W8txRQs9gx!KRk9r7lj0g{T6tzoqX-_dpLd| zc}a*fdEucEWCnfoy-}wfUXJw#wa!|X%SK|Wvx=>^9+g08MyeaGlZ*lvB2bETs3--^ z+wLO`AdtKJ?#u@Zsd0Ih5Dft}<(D?$bBc!XLHSqjdP0;~MCGtdW1kzy1&AjyxUS(( z-~8oS^x7v-cRr?z2PQQ6Zq9wHyho@aQtZVU!kEil!1T=LzS75WRAj$fhdWW4Mv-^; z_JZ6&$xmf$0MX1b)g(9Ja4rP@X^B!o$Gq`%4Mrw_Qkk| zsx(i;K-|#ST}t$MR*jZ|Q#g`Rdpj+eYM@saUHxEQQlH3+gpuXzEt_9?lw+yBlI(q; z1YTUjQER0Be%h2ZWO`0v6WKewc^rlNuTCZu$^^YWBISHyL@tUQ{jD@6?c-i3z6#AF z`Syfp$0zz@-*t)A!cbXn9U|yk0K{qIBXk1C(E)h``C)#I_(AEc+Mpq^8RAg)>+BfvKDEJ^tgQbKc5aTF%Em+A{W@>ZMYyoLh zppW?w)Ely(0ZIR(EM&lM7V)1F7MX+Yk*4DN({4-)b!fB@ zjv>tMVC|{nI_J&elzHw!z+GYi^Kc!yzQ0iQ$4@n>&-6;V73%A0+=%a)6Z(o3?KG`d zhCLC2BX*-QqMDvI@bn6n8j@u0Pcfn5w{WhnZg`Xhb=Qepe)I7D=w%sr|0S(Rz{4Hu zjy=d&n@d$d$y6RhDtw)Pfw-IF_E&psmHO{5b?L5~49?JD&QLM(FZSKHstA5|AEOU2 zqmVXYEHGMMz1D2lg0z?Qd=;h_-bm+GzsLiON%3SaE5IdJBJLcGKbeOJL)IILV=E|e zi;73B9=0_rEkr9R0$AvxXF%tKL#cSPIeu4_LYS-+CX4^xxLf^RdECilWXmi5xe+y- z2O3RwN_!h`b^B#{VD_qrZzEM?o&H+xHUW5o>{;K)-i*+Ieu;BDoV1-)_-{;8bMH_KUD146pelqjOK?es?-U3FBi0$x^mZ2Rd3bR zhMMF1DqM>^HnLOfF(t)a%CM=Do+A9rnBwCk7ytpz{~+Nw@pb0`?hdw+;&; z-Dh^yGX%&k%(S<6M2@r6_uA-50u$ma{1#B`p}N*|`_|-6*q<0~u3_=jeel-r(gIwm z`RxZGi!ay3di9|VVx@SSQtC!64Gp}1^3*x)GDW2nm9w`07kvvlMz>*hrxgcckXMp6 zt*yy9S{99&Or-5$*85Uxgo&k{{Ku}JCgIv#(|^ZDFL8~xeQ)tju7$3kZw47ZX#+UC zn$rp zQup#SX5JDXQe~Zif{T5Qi6Tk0Jcj+NASJ<0hDZGeK^i`kN@DhG*M9$YUvsERC0~Mm zjIq!X<+H>Z|8Xvy1003?vy1t9YIr2`m>iDfG= zizy)`EBo4zk?VgOrtZkh1-gGT57md_;3?ZIg$?tM7*ywZlY#3(EYv0nz9om&vG7~C zVPF;~!7~8G*#=L&T-zsXN?uNTJU-HE?inftS+i;uC#pXi=~#S!DVxc=H8iWzs3~4P zrNlDfB&s1KB|&!9MZxF(fHLlH*z92EaWN<_lJW?kis{P2(avdCKl?RQw~Ip#K2CEV zxuJOB#J&pR8EX1O%x_% zLzeOBzkzRh?On};Scdw;-}GK)shoK~YU}6s4Os7d{(5Knpqxxn;d^0`=UTZ3u0D?u zn;wW+gNT88br0GFq0ppQ;?|6I29c$Dq#NHSxhQThe&Lpeg=Z+0Sa6B0(6LUoLX_u4 zbV}IrO~ScJTtK%F^h)=T-157%5bq`txj+s8w&Q0R^0OK;lQcut6DB=If9?asxQ+Mp z{HV6SG9)W_k5lActkE0eTxZ_~dkqJ}dEevQKvg8MW;|_QrR&AaoD9cz8P|*+c^x|j zFlwC`H;D~3iK2H^lRu5L(zj7kqcUm!M^{LMo!~mCpA|}dE656GDfAnGUc3q|kEdi{9%YSC^IV9gdw7l15sZ%~=L*_t0QqKnWfk*UCWQ?4J67ctyu&H?K)h&6WRt?VlS4UFtec zGCwrXm{907&F_&20!y)y(Seaf)u$wU)(a(wI7x(>USgyKtF!r|^6@_E>FWAIFTKY2m>`u_OHQ`2)B>V;S>|4e98gCfx zgJmEHoNqr-4mcfb_}?O8%=gYx|7!tg@0J(W^sJktB% z)h!?HLt1)lbA~_93BSE;7xjBRbuuU=@H1m2H#HYyIqX1?!1?fi`M)q0SJp$hg7^^o z(u^qL+7oW}8sEXrkGo0upLNfMnS_X>pc$OFhu0)oH9q2Qg*)9+9o~sSQa;kGhTDo+ z79=r<-N7L-?f>y%-BR{mKrTuUD#}#6gJ~RR2`7^9i$w-C=8q~%h{~ZoKSJR{WWB4O z4|(M!O6b}~*n2$~to9?E{WkG_tYx9X6C7H}m#;?=2j*REdv|P+trJQ-spkE5*gnZe z2RtiLJgj85Ni^fNAhFFnugNs7ERvGBcoFn|a)Ec)c{1hI*X#U1{jqK<`>JDwn>^s= zxvf_NhCCQf;9O6wOjTP!5{>4qs(Oo68+kj3u()GLPz>)*BNg~%yUB|%G96U6AKb@Lb{exWYn(qjB`V? zt~nfKQwQqg($UAGMu10GsbMrUX&_Dn{VsV#A_J!ly0tUJ27wPJb8p+QoM%@nW` zZgtJ7ig_y?-0u1@J%p1T7@KIIWhq5bT(Y#d*j13G#V*S-gdnNnpP<5aH+&0luFCJ& z1;3T|Gn~joJwR?K6ejElF34YrH6-Eg1#rVH&eD?y(7sJ;qG`Nvd?5V zeRo!A_?Dwt@0{*l$OG415CJw_v!3cIN>|SI&Tq+9DrH<|<%iOmxgpJ?#$hHW1D3Tf z4N5)D#Z)SQhAAkPn00ts->+ie=HOA#ci)zG^^|kk16;gXE0lx$x2au zhH_7V6Jf`$;ff-+scYK#v$yP^uL3L^+sWf}2Xysmset<@Csyd9a^yo%O5e|^v8>5_ zxT`kb>5z?Pf2f8<06E*q%*w}gIXGOrKHo~LuKHot%L{ipWB(98FZKB)m+aO7wvMZF zt9*AB`Tu3-)0-DCzEs=BEDHU?%MKiaq`u`mbQu1sJvUU8o|V)m`5fxzCTbg zeTq4HBAr+&o@eNNOedj-@vv6hw9u0e4LqC{fQkrg_KLt+rx_x-%===bQlQNcSylAD zAcZEwK7+9A{_4xgF7*m)k+=8Y1B=AeG4qIe9;hfgcUNY?mhItfMHjl%NqFIeRldJy z$6naSD*IURSR?fO3>RD5ABlaE>gU!Rk4L06Hb(@I-Whr8>R6oB=%tGSLB zuzzLdsrtf0VDo!^`>N!n8ZoHowR2M6`SZOM`4NqdTtvA|UY3nXmBQmME(Sn=8J36m zZY95PJ4vzaS#C-*C9Er`OFt;>b*&wbah@NHa}C>Q_2P7}7uv?F1qfzqe%&;T`=5Kt s!@4YyYuoy89rz1N{x`eM#Rx}CqVUzTP53Exx18gwsnzMyQ|{6K0iLOqX8-^I literal 0 HcmV?d00001 diff --git a/documentation/manual/es-ES/src/main/resources/shared/images/AuthorWork.zargo b/documentation/manual/es-ES/src/main/docbook/images/AuthorWork.zargo similarity index 100% rename from documentation/manual/es-ES/src/main/resources/shared/images/AuthorWork.zargo rename to documentation/manual/es-ES/src/main/docbook/images/AuthorWork.zargo diff --git a/documentation/manual/es-ES/src/main/docbook/images/CustomerOrderProduct.png b/documentation/manual/es-ES/src/main/docbook/images/CustomerOrderProduct.png new file mode 100644 index 0000000000000000000000000000000000000000..7034cbe8cd54af08d478013a26a9f7432b779222 GIT binary patch literal 5035 zcma)AcUV)|whzN7qlku0jjcgHud^=yNTakp=0{N| zK3zSnvzGz}7i_uX->dFkg_VL5o+qxB|KX=03Y7n78^+k4PdnOj^smN4OfFQ7OvmDG zRLvs}z)_=71EC6emqbwWoGdQXChETpl>%4!_&plD1(VE^>`!t50H1e-OsG;z2>&eJ zuK^Yo+27=9pcxKus3!OHt|eSx4aDW;#>2^SIlM&TNVcj+fkZBrKPtOV?h_sB8vOfi z8t!q!o1QCFw0@zGZhJBiZ=cQuqs&DrXyOe@nE=q?s{a=Q#fN2 z4SbU@_2VQgp?}`_vWw9w>9i56DdtsxF^?gYzA<^*AgLozIz1QO%%wNIoY*A-=W??A z?Q>an@Q!*rnNFt)@VGJK*+x&tolUGwjZ{zI$#gu-eK}T012*HLV?m6NuCIWU%O>&k zYU+Vk@UpQNQli2`nc#yo9*02N?b8Gr?gI4(MMQTpB} zRC^x9QcCJ@1krlHR%v41uXki)dR}#!6TZfxHt~6u!N)OVGQBr3XquJ{^lS{GzfGcx zdm(wR9B}i|XK@Q3ct~(Nov1cO;8ZRS=YZvT=~R?a-qrh{l@mU5-^^XmZh>$qlNQK~ z3lr^a7Pn}=!3h=?T3t7n-&bPJ7!zK1JiepY9_Kw6JP2)v1wX5SP6&Lg@iBJ|P_!n$ z>duHo##N*h7T}BtC9b^(#t3F>-F44JfZZ4YioJMO zo@kk#zBfPO8hS78cfRHuW@JJcq)6+of38vR`|?Nbr10jf>}S;0oi}Ij3JUKx8nO&m z=T-@U@KluWl`zh>9kppxl5wXokLDn>FU3M;PBpull47|?pdoipw6?c`^7;$+At!NH z(_cR`sK2p$ z{tgV8L6t(*Ik2o-d~Ucp=ErW}rrZW0m$~fl^mRtmH`Q|a7ItYWxvL|TXg_?p^Ux@3 zxdOe;I#DSxY&5HjELFe&cqm{!{w$T^@Y*LJ{;K~sie`6mo;JQD)m_@hjpv~dIPGRCJF!?;u(J((^d;gh2WVFW z+)2Z{%||k_^45E*Jaust%dPncXdToJb;5#AsY%i0*H}X%wDi!!%6m3XsC$YLD6=X?HhA@xQx6GwlG4pIvoxmPYU|+jXL;*#$T;s>PuUpm>_p)G zGQaU@vhfvg%}Fug(UEENijbg`xb*q5*%+UZZP-eAtqprodeCDp+$L=IF(G<@wSDIS zZRQ@I0|lH8`-&G@IyTw%*Z=s^wa4WMxk%e%_vbV!5aizZsq$Xzm#YMwJ8!NI*c=YO z$u_x|DKyG>!RohNs#W!2>%;w&X&lEu%S92wSr+aT^LFZy#w6S8o2S;=Aw262uYl6A zBLzM(Y$b_+TNP)jf(m?@%7I~(YR||wZz?B#U4E%?DygMDt(WvxJ^h1vwMaZSScbYT z4x568>f?u6usJKcDh{6-^5YffV*C-9Ve^cv-~8Zg;rOfN)oND(dx1N!bEG3M3Gen5 z-RBbCfXa6AmMY-@%hggFBtipSpj_`sRBdHIe3~N`swEyIRvzEaN^nTN<8(#R3;l`L z7=8ezgd`N~X9?9)Z(ct9j$X!p1(9s^>ci zktMR*8`owJ^MBf$T%(gsVT0r-^G$4>wXeQ9*I3|pvuIoB#hR(tw8XkscM;yaf2^|0 zr-LIUB6NuwsD4TeewPBl=jKt90Ww!<(Lhn>LfwLyx zCU#`7NC1{;ma$+nTF}dg$Au9dLnE6XwjeV@T|pb4wS&J)p&3c4Q7Gv{D@5ji&sd`k zEuKI#%X>gd+rKYZ7pDjgeWpurS^NAt>6cUk&1(u4*$iS9#!c`SaH9HkT&4K1Vv#(B zRr(Y`h8*@SDZ;&5psWc6Qr;j*{t1ZZ^B+SS%3U9{m#b`oD1kCOhN2dXHDW^(-l0HD zNg}UHF;(+ABBlnq{@FNTau!$UO)3WeDCo_!l0$1$)nL_uXP=-m>2iy(e( zxi?@}$2**rnK>P7#JT_$wlHj5@b~tV-P(~i86Nw7&AaC~q?32V464L4PD%Icb#Zy0E$D1C=z-@F>XJb})uiYk5D!&GBmvZaw_ z)k^T_PJ!YZ)K)j(F^23D30^v{VD`fJlKoOg2+feoZ1(q8n{dI0huL&bVPaJ`&*p{WKQ{MXMMLPKO-J5Z{mx`F`P2*jjxB41oJi}(=Cc@)V zEEfnoYSz97qTk&vDz{IZuNo0^D|yDcf%|HO%SJAT6FU#*XkFhzTN*TlDjpyv9P^F~ zaq`8}Bnm2bOYC2ex7<3O`saASCstj`@DwAOrUFMR1(!x zF3-@%rH}FR{La5NXL&!>y_T92p}Io;$3JZ%bR*A0VTN#HtLDy5EQV74J|j8Ms`i;q z{Hu<}hn(~e-sb=h{9n5F|73;x3Lt|)?e$3XO#b7z9UybYORdCW<1h!k;0mF&C@I$9 zY8T1Xa3)eNHV=Ad7{{0Fqa#6SRRzugS*qsxBh&V~I&R#_FNr0+^)!#2X}1FA!beX@ z?)j|nIvpQ@)KK&w~5pI^aSXH2Ua=q`GOZ=v+37?oMJHvprO_F(`t%W(H zxH7aTK_Q76DP?A;WZK0Yq~5*O$1L4QYR@L6WOP31wWc{>IlkJYyN@$VgPkRI8VF|i zY&Y(xJkbLQ?A0hPD%qShuSM?6&e6yxe9o(v|m z@|W+=hk^?39#c)8EmFqMTqqxa2AR1knB#c)yE}@dn8w}}PMNyLUue}0UnqH}Jo+1O zrp4%QlQ59!#}~f;a3)ch-Bi5y*lqI%S_zZCo+hK8x;(T0^w7KHVAe%X*MR(Ryrmsx zb2xt@V8qIud7`Ui>iFKp&J<+hI*7WCTeXeIeYR#lzFc0sNW;Z{F=r*%SoEk=e?L0Z z&cDRn7$IW~!QMD0N6eF;H0QrYsBNp>u}1G$3F3szCO`frN}p9Hb}Gf?Wf1`~)y6la zIpufwE-_1+v)lBGMAonFJf4FIynAIX-OW zx8!WxTlYC;=^Kw=IH&2HHaBe0X5Bga;ci@=mqOc<2S8bYy*+{CcQ8kJI;xM5X#}FX zyc?3=++}yEb&r_km|fm05N5>v3z{S7LoG#_n-zW07@N~@d#ENx%RHA6`3)@Ry zblqbvOa^k#kxkU&Nqr>*;~QFG+e3l!3NvEE<{HDpYj}n;E-QF|S?b1E=$*9T6I)$$ z+tYe*INiRXJM(UnsETN_XUk9vZ*bZBN8prrCzjU?-lr#FDL#6w=0USr^-Z>QF)N-X zGZ0EXpdvu?$Ac9$+enNpBf5j3iphvi2?iDZ5Q-hwPN4HAeCnvnLe_A&J26H0=m`rb}hiZVheO2sSq; zR+S#)X}!MTUXS}gdFFe6Tx*!fkvk(QAj~WbtXv&TS;_KB#hh!An?8wv#u)n9&+@|w zPbwS#eRTh6aHKejb6F%MsbA;CE|_!I-z`z2_!^FGda5%vq_5ZVRs-a#o}FLS7PkEg z_BG9O5}$l~^m+JG1oW zTf6G`zQ%W%eTzJRqme>V70dhV5^_f13HEH*{k-ErQxbREMTy&s<72PeR&VJkfG7da zB0c5}6C)cQ?K`8l{>7}!bZ7r!+l9)Z+fuel4&bHS4=f?wv3(|a73I6E3Ww-xmyQ4U^dhQL!9|-&} zQzkQn@|B^rgh6J4ha#)r0%QFNJKp8wpswFX;1N|VVaR%UeRJ|>OHY&XmPi?;Z#BkW zjg*|xxgRKQ1=iPFX+|~}$x*#x2OT5B2MQly>7*Qn4W^|9)zaeoPJ;suI^EnyU{~!T zub6#P7&_|H(FPm%NAUkynA^=*8R}X$#Gycyurm_r)QpDG^QRT(_RHMsP>0O|cPfQX ziMtw|UP#(fqqMW1v}@!9S9C0>yDA#kG18CwDq|9Uvau~U>t4554Mf$B03oY1ceX#U zLcB2ZvS#mCB2}0a!Fj85-UQ)Tl4_H1ll0X0H!|?1{r)}zf0d*Jfi|T-XaW5qy_=`- zFdZI2nr#8jADwpN4`2y8`Ga5B?fTJ&|1-4&%NGjH?yaj>_!V#*#_(QrU7GZnXuca-hT4ErLJ||7feW8P z!2P?yM#GP~cs`tXueYRW_ZpGwLF8Z_D+bN;;UG`*rmQQXj)tiFx=h>wzH*!-6AFJy zY0zbJ8d~VGy*pvf@5?H;V~FX^Utb5I>?Z z&jmOvkucdolI}O-R;;h)=ghBPMbmk|AoetG66#j0`xH&qHwr~qTuz9wzQDQJQ-qzp z@N?a5u;I^1M~I`)1M$&UBfLcP0~aKG`>i{s2!+3bd;1YLR_#%m|JA9ApcMOh15Qo~ t$88P=kufyt8yB4ywax)^-oHl|@$(T;mQk2VLH=k%>76&y%0K52@;{dj%ccMT literal 0 HcmV?d00001 diff --git a/documentation/manual/es-ES/src/main/resources/shared/images/CustomerOrderProduct.zargo b/documentation/manual/es-ES/src/main/docbook/images/CustomerOrderProduct.zargo similarity index 100% rename from documentation/manual/es-ES/src/main/resources/shared/images/CustomerOrderProduct.zargo rename to documentation/manual/es-ES/src/main/docbook/images/CustomerOrderProduct.zargo diff --git a/documentation/manual/es-ES/src/main/docbook/images/EmployerEmployee.png b/documentation/manual/es-ES/src/main/docbook/images/EmployerEmployee.png new file mode 100644 index 0000000000000000000000000000000000000000..a7ecff483fe4fa6684458b07ee0063f522c497cb GIT binary patch literal 8512 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 F{{m>Ea;E?Q literal 0 HcmV?d00001 diff --git a/documentation/manual/es-ES/src/main/resources/shared/images/EmployerEmployee.zargo b/documentation/manual/es-ES/src/main/docbook/images/EmployerEmployee.zargo similarity index 100% rename from documentation/manual/es-ES/src/main/resources/shared/images/EmployerEmployee.zargo rename to documentation/manual/es-ES/src/main/docbook/images/EmployerEmployee.zargo diff --git a/documentation/manual/es-ES/src/main/docbook/images/full_cream.png b/documentation/manual/es-ES/src/main/docbook/images/full_cream.png new file mode 100644 index 0000000000000000000000000000000000000000..4f174a0b05e2f938563e3db7031029171000f0b1 GIT binary patch literal 9359 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 literal 0 HcmV?d00001 diff --git a/documentation/manual/es-ES/src/main/resources/shared/images/overview.svg b/documentation/manual/es-ES/src/main/docbook/images/overview.svg similarity index 100% rename from documentation/manual/es-ES/src/main/resources/shared/images/overview.svg rename to documentation/manual/es-ES/src/main/docbook/images/overview.svg diff --git a/documentation/manual/es-ES/src/main/docbook/legal_notice.xml b/documentation/manual/es-ES/src/main/docbook/legal_notice.xml new file mode 100644 index 0000000000..1fe3fba20b --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/legal_notice.xml @@ -0,0 +1,52 @@ + + + + + + Legal Notice + +
+ 1801 Varsity Drive + Raleigh, NC27606-2072USA + Phone: +1 919 754 3700 + Phone: 888 733 4281 + Fax: +1 919 754 3701 + PO Box 13588Research Triangle Park, NC27709USA +
+
+ + Copyright 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 http://www.opencontent.org/openpub/). + + + Distribution of substantively modified versions of this document is prohibited without the explicit permission of the copyright holder. + + + 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. + + + Red Hat and the Red Hat "Shadow Man" logo are registered trademarks of Red Hat, Inc. in the United States and other countries. + + + All other trademarks referenced herein are the property of their respective owners. + + + The GPG fingerprint of the security@redhat.com key is: + + + CA 20 86 86 2B D6 9D FC 65 F6 EC C4 21 91 80 CD DB 42 A6 0E + +
\ No newline at end of file diff --git a/documentation/manual/es-ES/src/main/docbook/legal_notice2.xml b/documentation/manual/es-ES/src/main/docbook/legal_notice2.xml new file mode 100644 index 0000000000..db062f4e56 --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/legal_notice2.xml @@ -0,0 +1,16 @@ + + + + + Translation-specific Legal Notice + + 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. + + \ No newline at end of file diff --git a/documentation/manual/es-ES/src/main/docbook/translators.xml b/documentation/manual/es-ES/src/main/docbook/translators.xml new file mode 100644 index 0000000000..23c8999507 --- /dev/null +++ b/documentation/manual/es-ES/src/main/docbook/translators.xml @@ -0,0 +1,10 @@ + + + + + + + + kreimer@bbs.frc.utn.edu.ar + + \ No newline at end of file diff --git a/documentation/manual/es-ES/src/main/resources/shared/css/html.css b/documentation/manual/es-ES/src/main/resources/shared/css/html.css deleted file mode 100644 index d6342f562a..0000000000 --- a/documentation/manual/es-ES/src/main/resources/shared/css/html.css +++ /dev/null @@ -1,97 +0,0 @@ -A { - color: #003399; -} - -A:active { - color: #003399; -} - -A:visited { - color: #888888; -} - -P, OL, UL, LI, DL, DT, DD, BLOCKQUOTE { - color: #000000; -} - -TD, TH, SPAN { - color: #000000; -} - -BLOCKQUOTE { - margin-right: 0px; -} - - -H1, H2, H3, H4, H5, H6 { - color: #000000; - font-weight:500; - margin-top:10px; - padding-top:15px; -} - -TABLE { - border-collapse: collapse; - border-spacing:0; - border: 1px thin black; - empty-cells: hide; -} - -TD { - padding: 4pt; -} - -H1 { font-size: 150%; } -H2 { font-size: 140%; } -H3 { font-size: 110%; font-weight: bold; } -H4 { font-size: 110%; font-weight: bold;} -H5 { font-size: 100%; font-style: italic; } -H6 { font-size: 100%; font-style: italic; } - -TT { -font-size: 90%; - font-family: "Courier New", Courier, monospace; - color: #000000; -} - -PRE { -font-size: 100%; - padding: 5px; - border-style: solid; - border-width: 1px; - border-color: #CCCCCC; - background-color: #F4F4F4; -} - -UL, OL, LI { - list-style: disc; -} - -HR { - width: 100%; - height: 1px; - background-color: #CCCCCC; - border-width: 0px; - padding: 0px; - color: #CCCCCC; -} - -.variablelist { - padding-top: 10; - padding-bottom:10; - margin:0; -} - -.itemizedlist, UL { - padding-top: 0; - padding-bottom:0; - margin:0; -} - -.term { - font-weight:bold; -} - - - - diff --git a/documentation/manual/es-ES/src/main/resources/shared/images/AuthorWork.gif b/documentation/manual/es-ES/src/main/resources/shared/images/AuthorWork.gif deleted file mode 100644 index d0fb5125fae573eb18bbec7c0532a3b930d92598..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7186 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 Jzdn5d06Sf(cC7#a diff --git a/documentation/manual/es-ES/src/main/resources/shared/images/EmployerEmployee.gif b/documentation/manual/es-ES/src/main/resources/shared/images/EmployerEmployee.gif deleted file mode 100644 index 112e9b4f081a808a2a377268117846ead75ef188..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9779 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 Nebsk;H>3an06X0OQB?o{ diff --git a/documentation/manual/es-ES/src/main/resources/shared/images/full_cream.gif b/documentation/manual/es-ES/src/main/resources/shared/images/full_cream.gif deleted file mode 100644 index ef15d691005227f27f73afed4d5cf019f44d976d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9286 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 UUW>n8N3&kfsh*iA3;^W+A4-9>hX4Qo diff --git a/documentation/manual/es-ES/src/main/resources/shared/images/lite.gif b/documentation/manual/es-ES/src/main/resources/shared/images/lite.gif deleted file mode 100644 index fd34bcec0956e9116ba4feb018330b17b20e8a62..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6764 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 RJlJa(5?pWz2n7I{{{w0rUp)W- diff --git a/documentation/manual/es-ES/src/main/resources/shared/images/overview.gif b/documentation/manual/es-ES/src/main/resources/shared/images/overview.gif deleted file mode 100644 index d7dfda915c6dfd6a4096973f2a936bca743ef87d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8578 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 Xj