Author: xhuang(a)jboss.com
Date: 2007-10-27 08:53:39 -0400 (Sat, 27 Oct 2007)
New Revision: 14153
Modified:
core/trunk/documentation/manual/es-ES/src/main/docbook/content/association_mapping.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/basic_mapping.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/batch.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/collection_mapping.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/configuration.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/events.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/inheritance_mapping.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/performance.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/persistent_classes.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/query_hql.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/query_sql.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/session_api.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/toolset_guide.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/transactions.xml
core/trunk/documentation/manual/es-ES/src/main/docbook/content/tutorial.xml
Log:
Match to latest English XML
Modified:
core/trunk/documentation/manual/es-ES/src/main/docbook/content/association_mapping.xml
===================================================================
---
core/trunk/documentation/manual/es-ES/src/main/docbook/content/association_mapping.xml 2007-10-27
03:50:07 UTC (rev 14152)
+++
core/trunk/documentation/manual/es-ES/src/main/docbook/content/association_mapping.xml 2007-10-27
12:53:39 UTC (rev 14153)
@@ -332,6 +332,45 @@
create table Address ( addressId bigint not null primary key )
]]></programlisting>
+
+ <para> UNTRANSLATED!
+ If you use a <literal>List</literal> (or other indexed collection) you
need
+ to set the <literal>key</literal> column of the foreign key to
<literal>not null</literal>,
+ and let Hibernate manage the association from the collections side to maintain the
index
+ of each element (making the other side virtually inverse by setting
+ <literal>update="false"</literal> and
<literal>insert="false"</literal>):
+ </para>
+
+ <programlisting><![CDATA[<class name="Person">
+ <id name="id"/>
+ ...
+ <many-to-one name="address"
+ column="addressId"
+ not-null="true"
+ insert="false"
+ update="false"/>
+ </class>
+
+ <class name="Address">
+ <id name="id"/>
+ ...
+ <list name="people">
+ <key column="addressId" not-null="true"/>
+ <list-index column="peopleIdx"/>
+ <one-to-many class="Person"/>
+ </list>
+ </class>]]></programlisting>
+
+ <para>UNTRANSLATED!
+ It is important that you define
<literal>not-null="true"</literal> on the
+ <literal><key></literal> element of the collection mapping if
the
+ underlying foreign key column is <literal>NOT NULL</literal>. Don't
only
+ declare <literal>not-null="true"</literal> on a possible nested
+ <literal><column></literal> element, but on the
<literal><key></literal>
+ element.
+ </para>
+
+
</sect2>
<sect2 id="assoc-bidirectional-121">
Modified:
core/trunk/documentation/manual/es-ES/src/main/docbook/content/basic_mapping.xml
===================================================================
---
core/trunk/documentation/manual/es-ES/src/main/docbook/content/basic_mapping.xml 2007-10-27
03:50:07 UTC (rev 14152)
+++
core/trunk/documentation/manual/es-ES/src/main/docbook/content/basic_mapping.xml 2007-10-27
12:53:39 UTC (rev 14153)
@@ -111,7 +111,59 @@
búsquedas del DTD usando una conexión de Internet,
chequea tu declaración
de DTD contra la contenida en el classpath.
</para>
- </sect2>
+ <sect3 id="mapping-declaration-entity-resolution">
+ <title>UNTRANSLATED! EntityResolver</title>
+ <para>
+ As mentioned previously, Hibernate will first attempt to resolve DTDs in its
classpath. The
+ manner in which it does this is by registering a custom
<literal>org.xml.sax.EntityResolver</literal>
+ implementation with the SAXReader it uses to read in the xml files. This custom
+ <literal>EntityResolver</literal> recognizes two different systemId
namespaces.
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ a <literal>hibernate namespace</literal> is recognized whenever the
+ resolver encounteres a systemId starting with
+ <
literal>http://hibernate.sourceforge.net/</literal>; the resolver
+ attempts to resolve these entities via the classlaoder which loaded
+ the Hibernate classes.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ a <literal>user namespace</literal> is recognized whenever the
+ resolver encounteres a systemId using a
<literal>classpath://</literal>
+ URL protocol; the resolver will attempt to resolve these entities
+ via (1) the current thread context classloader and (2) the
+ classloader which loaded the Hibernate classes.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ An example of utilizing user namespacing:
+ </para>
+ <programlisting><![CDATA[<?xml version="1.0"?>
+ <!DOCTYPE hibernate-mapping PUBLIC
+ "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+ "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" [
+ <!ENTITY types SYSTEM "classpath://your/domain/types.xml">
+ ]>
+
+ <hibernate-mapping package="your.domain">
+ <class name="MyEntity">
+ <id name="id" type="my-custom-id-type">
+ ...
+ </id>
+ <class>
+ &types;
+ </hibernate-mapping>]]></programlisting>
+ <para>
+ Where <literal>types.xml</literal> is a resource in the
<literal>your.domain</literal>
+ package and contains a custom <link
linkend="mapping-types-custom">typedef</link>.
+ </para>
+ </sect3>
+
+ </sect2>
<sect2 id="mapping-declaration-mapping" revision="3">
<title>hibernate-mapping</title>
@@ -758,6 +810,21 @@
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><literal>UNTRANSLATED!
sequence-identity</literal></term>
+ <listitem>
+ <para>
+ a specialized sequence generation strategy which utilizes a
+ database sequence for the actual value generation, but combines
+ this with JDBC3 getGeneratedKeys to actually return the generated
+ identifier value as part of the insert statement execution. This
+ strategy is only known to be supported on Oracle 10g drivers
+ targetted for JDK 1.4. Note comments on these insert statements
+ are disabled due to a bug in the Oracle drivers.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</para>
@@ -877,6 +944,172 @@
</sect3>
</sect2>
+ <sect2 id="mapping-declaration-id-enhanced">
+ <title>Enhanced identifier generators</title>
+
+ <para>
+ Starting with release 3.2.3, there are 2 new generators which represent a re-thinking
of 2 different
+ aspects of identifier generation. The first aspect is database portability; the
second is optimization
+ (not having to query the database for every request for a new identifier value).
These two new
+ generators are intended to take the place of some of the named generators described
above (starting
+ in 3.3.x); however, they are included in the current releases and can be referenced by
FQN.
+ </para>
+
+ <para>
+ The first of these new generators is
<literal>org.hibernate.id.enhanced.SequenceStyleGenerator</literal>
+ which is intended firstly as a replacement for the
<literal>sequence</literal> generator and secondly as
+ a better portability generator than <literal>native</literal> (because
<literal>native</literal>
+ (generally) chooses between <literal>identity</literal> and
<literal>sequence</literal> which have
+ largely different semantics which can cause subtle isssues in applications eyeing
portability).
+ <literal>org.hibernate.id.enhanced.SequenceStyleGenerator</literal>
however achieves portability in
+ a different manner. It chooses between using a table or a sequence in the database to
store its
+ incrementing values depending on the capabilities of the dialect being used. The
difference between this
+ and <literal>native</literal> is that table-based and sequence-based
storage have the same exact
+ semantic (in fact sequences are exactly what Hibernate tries to emmulate with its
table-based
+ generators). This generator has a number of configuration parameters:
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>sequence_name</literal> (optional, defaults to
<literal>hibernate_sequence</literal>):
+ The name of the sequence (or table) to be used.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>initial_value</literal> (optional, defaults to
<literal>1</literal>): The initial
+ value to be retrieved from the sequence/table. In sequence creation terms, this is
analogous
+ to the clause typical named "STARTS WITH".
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>increment_size</literal> (optional, defaults to
<literal>1</literal>): The value by
+ which subsequent calls to the sequence/table should differ. In sequence creation
terms, this
+ is analogous to the clause typical named "INCREMENT BY".
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>force_table_use</literal> (optional, defaults to
<literal>false</literal>): Should
+ we force the use of a table as the backing structure even though the dialect might
support
+ sequence?
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>value_column</literal> (optional, defaults to
<literal>next_val</literal>): Only
+ relevant for table structures! The name of the column on the table which is used
to
+ hold the value.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>optimizer</literal> (optional, defaults to
<literal>none</literal>):
+ See <xref linkend="mapping-declaration-id-enhanced-optimizers"/>
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ The second of these new generators is
<literal>org.hibernate.id.enhanced.TableGenerator</literal> which
+ is intended firstly as a replacement for the <literal>table</literal>
generator (although it actually
+ functions much more like
<literal>org.hibernate.id.MultipleHiLoPerTableGenerator</literal>) and
secondly
+ as a re-implementation of
<literal>org.hibernate.id.MultipleHiLoPerTableGenerator</literal> utilizing
the
+ notion of pluggable optimiziers. Essentially this generator defines a table capable
of holding
+ a number of different increment values simultaneously by using multiple distinctly
keyed rows. This
+ generator has a number of configuration parameters:
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>table_name</literal> (optional, defaults to
<literal>hibernate_sequences</literal>):
+ The name of the table to be used.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>value_column_name</literal> (optional, defaults to
<literal>next_val</literal>):
+ The name of the column on the table which is used to hold the value.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>segment_column_name</literal> (optional, defaults to
<literal>sequence_name</literal>):
+ The name of the column on the table which is used to hold the "segement
key". This is the
+ value which distinctly identifies which increment value to use.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>segment_value</literal> (optional, defaults to
<literal>default</literal>):
+ The "segment key" value for the segment from which we want to pull
increment values for
+ this generator.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>segment_value_length</literal> (optional, defaults to
<literal>255</literal>):
+ Used for schema generation; the column size to create this segment key column.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>initial_value</literal> (optional, defaults to
<literal>1</literal>):
+ The initial value to be retrieved from the table.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>increment_size</literal> (optional, defaults to
<literal>1</literal>):
+ The value by which subsequent calls to the table should differ.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>optimizer</literal> (optional, defaults to
<literal></literal>):
+ See <xref linkend="mapping-declaration-id-enhanced-optimizers"/>
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </sect2>
+
+ <sect2 id="mapping-declaration-id-enhanced-optimizers">
+ <title>Identifier generator optimization</title>
+ <para>
+ For identifier generators which store values in the database, it is inefficient for
them to hit the
+ database on each and every call to generate a new identifier value. Instead,
you'd ideally want to
+ group a bunch of them in memory and only hit the database when you have exhausted your
in-memory
+ value group. This is the role of the pluggable optimizers. Currently only the two
enhanced generators
+ (<xref linkend="mapping-declaration-id-enhanced"/> support this
notion.
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>none</literal> (generally this is the default if no optimizer
was specified): This
+ says to not perform any optimizations, and hit the database each and every
request.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>hilo</literal>: applies a hi/lo algorithm around the database
retrieved values. The
+ values from the database for this optimizer are expected to be sequential. The
values
+ retrieved from the database structure for this optimizer indicates the "group
number"; the
+ <literal>increment_size</literal> is multiplied by that value in memory
to define a group
+ "hi value".
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>pooled</literal>: like was discussed for
<literal>hilo</literal>, this optimizers
+ attempts to minimize the number of hits to the database. Here, however, we simply
store
+ the starting value for the "next group" into the database structure
rather than a sequential
+ value in combination with an in-memory grouping algorithm.
<literal>increment_size</literal>
+ here refers to the values coming from the database.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </sect2>
+
<sect2 id="mapping-declaration-compositeid"
revision="2">
<title>composite-id</title>
@@ -920,6 +1153,53 @@
compuesto está implementado como una clase separada en
<xref linkend="components-compositeid"/>.
Los atributos descriptos debajo solamente se aplican a este enfoque
alternativo:
</para>
+
+ <para>
+ A second approach is what we call a <emphasis>mapped</emphasis>
composite identifier,
+ where the identifier properties named inside the
<literal><composite-id></literal>
+ element are duplicated on both the persistent class and a separate identifier
class.
+ </para>
+
+ <programlisting><![CDATA[<composite-id class="MedicareId"
mapped="true">
+ <key-property name="medicareNumber"/>
+ <key-property name="dependent"/>
+ </composite-id>]]></programlisting>
+
+ <para>
+ In this example, both the composite identifier class,
<literal>MedicareId</literal>,
+ and the entity class itself have properties named
<literal>medicareNumber</literal>
+ and <literal>dependent</literal>. The identifier class must override
+ <literal>equals()</literal> and
<literal>hashCode()</literal> and implement.
+ <literal>Serializable</literal>. The disadvantage of this approach is
quite
+ obvious—code duplication.
+ </para>
+
+ <para>
+ The following attributes are used to specify a mapped composite identifier:
+ </para>
+
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ <literal>mapped</literal> (optional, defaults to
<literal>false</literal>):
+ indicates that a mapped composite identifier is used, and that the contained
+ property mappings refer to both the entity class and the composite identifier
+ class.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>class</literal> (optional, but required for a mapped
composite identifier):
+ The class used as a composite identifier.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ We will describe a third, even more convenient approach where the composite
identifier
+ is implemented as a component class in <xref
linkend="components-compositeid"/>. The
+ attributes described below apply only to this alternative approach:
+ </para>
<itemizedlist spacing="compact">
<listitem>
@@ -927,6 +1207,11 @@
<literal>name</literal> (opcional): Una propiedad de
tipo componente que tiene el identificador
compuesto (ver siguiente sección).
</para>
+ </listitem> <listitem>
+ <para>
+ <literal>access</literal> (optional - defaults to
<literal>property</literal>):
+ The strategy Hibernate should use for accessing the property value.
+ </para>
</listitem>
<listitem>
<para>
@@ -934,20 +1219,12 @@
por reflección): La clase del componente usado como
identificador compuesto (ver siguiente sección).
</para>
</listitem>
- <listitem>
- <para>
- <literal>unsaved-value</literal> (opcional - por
defecto a <literal>undefined</literal>):
- Indica que las instancias transitorias deben ser consideradas
como recién instanciadas,
- si se establece a <literal>any</literal>, o
separadas, si se establece a <literal>none</literal>.
- Lo mejor
-
- Indicates that transient instances should be considered newly
instantiated, if set
- to <literal>any</literal>, or detached, if set to
<literal>none</literal>.
- Lo mejor en todos los casos es dejar el valor por defecto.
- </para>
- </listitem>
+
</itemizedlist>
-
+ <para>
+ This third approach, an <emphasis>identifier component</emphasis> is
the one we recommend
+ for almost all applications.
+ </para>
</sect2>
<sect2 id="mapping-declaration-discriminator"
revision="3">
@@ -1099,6 +1376,21 @@
propiedad identificadora.)
</para>
</callout>
+ <callout arearefs="version6">
+ <para> UNTRANSLATED!
+ <literal>generated</literal> (optional - defaults to
<literal>never</literal>):
+ Specifies that this version property value is actually generated by the
database.
+ See the discussion of <link linkend="mapping-generated">generated
properties</link>.
+ </para>
+ </callout>
+ <callout arearefs="version7">
+ <para>UNTRANSLATED!
+ <literal>insert</literal> (optional - defaults to
<literal>true</literal>):
+ Specifies whether the version column should be included in SQL insert
statements.
+ May be set to <literal>false</literal> if and only if the database
column
+ is defined with a default value of <literal>0</literal>.
+ </para>
+ </callout>
</calloutlist>
</programlistingco>
@@ -1172,7 +1464,26 @@
(<literal>undefined</literal> especifica que debe
usarse el valor de la propiedad
identificadora.)
</para>
- </callout>
+ </callout> <callout arearefs="timestamp5">
+ <para> UNTRANSLATED!
+ <literal>source</literal> (optional - defaults to
<literal>vm</literal>):
+ From where should Hibernate retrieve the timestamp value? From the database,
+ or from the current JVM? Database-based timestamps incur an overhead because
+ Hibernate must hit the database in order to determine the "next value",
+ but will be safer for use in clustered environments. Note also, that not
+ all <literal>Dialect</literal>s are known to support retrieving of the
+ database's current timestamp, while others might be unsafe for usage
+ in locking due to lack of precision (Oracle 8 for example).
+ </para>
+ </callout>
+ <callout arearefs="timestamp6">
+ <para> UNTRANSLATED!
+ <literal>generated</literal> (optional - defaults to
<literal>never</literal>):
+ Specifies that this timestamp property value is actually generated by the database.
+ See the discussion of <link linkend="mapping-generated">generated
properties</link>.
+ </para>
+ </callout>
+
</calloutlist>
</programlistingco>
@@ -1295,6 +1606,12 @@
de un bloqueo optimista. En otras palabras, determina si debe
ocurrir un incremento de versión
cuando la propiedad este sucia (desactualizada).
</para>
+ </callout> <callout arearefs="property12">
+ <para> UNTRANSLATED!
+ <literal>generated</literal> (optional - defaults to
<literal>never</literal>):
+ Specifies that this property value is actually generated by the database.
+ See the discussion of <link linkend="mapping-generated">generated
properties</link>.
+ </para>
</callout>
</calloutlist>
</programlistingco>
@@ -1580,6 +1897,9 @@
Si la clave única referenciada abarca múltiples
propiedades de la entidad asociada,
debes mapear las propiedades dentro de un elemento
<literal><properties></literal>.
</para>
+ <para>UNTRANSLATED!
+ If the referenced unique key is the property of a component, you may specify a
property path:
+ </para>
</sect2>
@@ -1686,6 +2006,10 @@
la aplicación de proxies es imposible e Hibernate
traerá temprano la
asociación!</emphasis>
</para>
+ </callout> <callout arearefs="onetoone10">
+ <para>
+ <literal>entity-name</literal> (optional): The entity name of the
associated class.
+ </para>
</callout>
</calloutlist>
</programlistingco>
@@ -2075,33 +2399,13 @@
</calloutlist>
</programlistingco>
- <para>
- Cada subclase debe declarar sus propias propiedades persistentes y
subclases.
- Se asume que las propiedades
<literal><version></literal> y
<literal><id></literal>
- son heredadas de la clase raíz. Cada subclase en una
jerarquía debe
- definir un <literal>discriminator-value</literal>
único. Si no se especifica ninguno,
- se usa el nombre completamente cualificado de clase Java.
+ <para> UNTRANSLATED!
+ Each subclass should declare its own persistent properties and subclasses.
+ <literal><version></literal> and
<literal><id></literal> properties
+ are assumed to be inherited from the root class. Each subclass in a heirarchy must
+ define a unique <literal>discriminator-value</literal>. If none is
specified, the
+ fully qualified Java class name is used.
</para>
-
- <para>
- Es posible definir mapeos <literal>subclass</literal>,
<literal>union-subclass</literal>,
- y <literal>joined-subclass</literal> en documentos de mapeo
separados, directamente debajo
- de <literal>hibernate-mapping</literal>. Esto te permite extender
una jerarquía de clases
- con sólo agregar un nuevo fichero de mapeo. Debes especificar un
atributo
- <literal>extends</literal> en el mapeo de la subclase,
mencionando una superclase previamente mapeada.
- Nota: Previamente esta funcionalidad hacía importante el orden de
los documentos de mapeo.
- Desde Hibernate3, el orden de los ficheros de mapeo no importa cuando se usa
la palabra reservada
- extends. El orden dentro de un mismo fichero de mapeo todavía
necesita ser definido como
- superclases antes de subclases.
- </para>
-
- <programlisting><![CDATA[
-<hibernate-mapping>
- <subclass name="DomesticCat" extends="Cat"
discriminator-value="D">
- <property name="name" type="string"/>
- </subclass>
-</hibernate-mapping>]]></programlisting>
-
<para>
Para información acerca de mapeos de herencia, ver <xref
linkend="inheritance"/>.
</para>
@@ -2871,7 +3175,24 @@
ser malo e inconsistente).
</para>
</listitem>
- </varlistentry>
+ </varlistentry> <varlistentry>
+ <term>
+ <literal>UNTRANSLATED! imm_date, imm_time, imm_timestamp, imm_calendar,
imm_calendar_date,
+ imm_serializable, imm_binary</literal>
+ </term>
+ <listitem>
+ <para>
+ Type mappings for what are usually considered mutable Java types, where
+ Hibernate makes certain optimizations appropriate only for immutable
+ Java types, and the application treats the object as immutable. For
+ example, you should not call <literal>Date.setTime()</literal> for an
+ instance mapped as <literal>imm_timestamp</literal>. To change the
+ value of the property, and have that change made persistent, the
+ application must assign a new (nonidentical) object to the property.
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</para>
Modified: core/trunk/documentation/manual/es-ES/src/main/docbook/content/batch.xml
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/batch.xml 2007-10-27
03:50:07 UTC (rev 14152)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/batch.xml 2007-10-27
12:53:39 UTC (rev 14153)
@@ -31,14 +31,20 @@
</para>
<programlisting><![CDATA[hibernate.jdbc.batch_size
20]]></programlisting>
-
+<para id="disablebatching" revision="1">
+ UNTRANSLATED! Note that Hibernate disables insert batching at the JDBC level
transparently if you
+ use an <literal>identiy</literal> identifier generator.
+ </para>
<para>
Podrías además querer hacer este tipo de trabajo en un proceso donde la
interacción con el caché de
segundo nivel esté completamente deshabilitado:
</para>
<programlisting><![CDATA[hibernate.cache.use_second_level_cache
false]]></programlisting>
-
+<para> UNTRANSLATED!
+ However, this is not absolutely necessary, since we can explicitly set the
+ <literal>CacheMode</literal> to disable interaction with the second-level
cache.
+ </para>
<sect1 id="batch-inserts">
<title>Inserciones en lote</title>
@@ -96,7 +102,57 @@
session.close();]]></programlisting>
</sect1>
-
+
+ <sect1 id="batch-statelesssession">
+ <title>UNTRANSLATED! The StatelessSession interface</title>
+ <para>
+ Alternatively, Hibernate provides a command-oriented API that may be used for
+ streaming data to and from the database in the form of detached objects. A
+ <literal>StatelessSession</literal> has no persistence context
associated
+ with it and does not provide many of the higher-level life cycle semantics.
+ In particular, a stateless session does not implement a first-level cache nor
+ interact with any second-level or query cache. It does not implement
+ transactional write-behind or automatic dirty checking. Operations performed
+ using a stateless session do not ever cascade to associated instances. Collections
+ are ignored by a stateless session. Operations performed via a stateless session
+ bypass Hibernate's event model and interceptors. Stateless sessions are
vulnerable
+ to data aliasing effects, due to the lack of a first-level cache. A stateless
+ session is a lower-level abstraction, much closer to the underlying JDBC.
+ </para>
+
+ <programlisting><![CDATA[StatelessSession session =
sessionFactory.openStatelessSession();
+ Transaction tx = session.beginTransaction();
+
+ ScrollableResults customers =
session.getNamedQuery("GetCustomers")
+ .scroll(ScrollMode.FORWARD_ONLY);
+ while ( customers.next() ) {
+ Customer customer = (Customer) customers.get(0);
+ customer.updateStuff(...);
+ session.update(customer);
+ }
+
+ tx.commit();
+ session.close();]]></programlisting>
+
+ <para>
+ Note that in this code example, the <literal>Customer</literal>
instances returned
+ by the query are immediately detached. They are never associated with any
persistence
+ context.
+ </para>
+
+ <para>
+ The <literal>insert(), update()</literal> and
<literal>delete()</literal> operations
+ defined by the <literal>StatelessSession</literal> interface are
considered to be
+ direct database row-level operations, which result in immediate execution of a SQL
+ <literal>INSERT, UPDATE</literal> or
<literal>DELETE</literal> respectively. Thus,
+ they have very different semantics to the <literal>save(),
saveOrUpdate()</literal>
+ and <literal>delete()</literal> operations defined by the
<literal>Session</literal>
+ interface.
+ </para>
+
+ </sect1>
+
+
<sect1 id="batch-direct">
<title>update/delete en masa</title>
@@ -125,14 +181,17 @@
</listitem>
<listitem>
<para>
- Puede haber sólo una clase mencionada en la cláusula-from, y
<emphasis>no puede</emphasis>
- tener un alias.
+ There can only be a single entity named in the from-clause; it can optionally be
+ aliased. If the entity name is aliased, then any property references must
+ be qualified using that alias; if the entity name is not aliased, then it is
+ illegal for any property references to be qualified.
</para>
</listitem>
<listitem>
<para>
- No puede especificarse ningún join (bien implícito o explícito) en
una consulta masiva de HQL.
- Pueden usarse subconsultas en la cláusula-where.
+ No <link linkend="queryhql-joins-forms">joins</link> (either
implicit or explicit)
+ can be specified in a bulk HQL query. Sub-queries may be used in the where-clause;
+ the subqueries, themselves, may contain joins.
</para>
</listitem>
<listitem>
@@ -144,24 +203,50 @@
<para>
Como un ejemplo, para ejecutar un <literal>UPDATE</literal> HQL,
usa el
- método <literal>Query.executeUpdate()</literal>:
+ método <literal>Query.executeUpdate()</literal>(the method is named for
+ those familiar with JDBC's
<literal>PreparedStatement.executeUpdate()</literal>):
</para>
- <programlisting><![CDATA[Session session =
sessionFactory.openSession();
- Transaction tx = session.beginTransaction();
+
+ <programlisting><![CDATA[Session session = sessionFactory.openSession();
+ Transaction tx = session.beginTransaction();
+
+ String hqlUpdate = "update Customer c set c.name = :newName where c.name =
:oldName";
+ // or String hqlUpdate = "update Customer set name = :newName where name =
:oldName";
+ int updatedEntities = s.createQuery( hqlUpdate )
+ .setString( "newName", newName )
+ .setString( "oldName", oldName )
+ .executeUpdate();
+ tx.commit();
+ session.close();]]></programlisting>
+
+ <para>
+ HQL <literal>UPDATE</literal> statements, by default do not effect the
+ <link linkend="mapping-declaration-version">version</link>
+ or the <link
linkend="mapping-declaration-timestamp">timestamp</link> property
values
+ for the affected entities; this is in keeping with the EJB3 specification. However,
+ you can force Hibernate to properly reset the <literal>version</literal>
or
+ <literal>timestamp</literal> property values through the use of a
<literal>versioned update</literal>.
+ This is achieved by adding the <literal>VERSIONED</literal> keyword after
the <literal>UPDATE</literal>
+ keyword.
+ </para>
+ <programlisting><![CDATA[Session session = sessionFactory.openSession();
+ Transaction tx = session.beginTransaction();
+ String hqlVersionedUpdate = "update versioned Customer set name = :newName
where name = :oldName";
+ int updatedEntities = s.createQuery( hqlUpdate )
+ .setString( "newName", newName )
+ .setString( "oldName", oldName )
+ .executeUpdate();
+ tx.commit();
+ session.close();]]></programlisting>
+
+ <para>
+ Note that custom version types
(<literal>org.hibernate.usertype.UserVersionType</literal>)
+ are not allowed in conjunction with a <literal>update versioned</literal>
statement.
+ </para>
- String hqlUpdate = "update Customer set name = :newName where name =
:oldName";
- int updatedEntities = s.createQuery( hqlUpdate )
- .setString( "newName", newName )
- .setString( "oldName", oldName )
- .executeUpdate();
- tx.commit();
- session.close();]]></programlisting>
-
<para>
- Para ejecutar un <literal>DELETE</literal> HQL, usa el mismo
método <literal>Query.executeUpdate()</literal>
- (el método está nombrado para aquellos familiarizados con
- <literal>PreparedStatement.executeUpdate()</literal> de JDBC):
+ Para ejecutar un <literal>DELETE</literal> HQL, usa el mismo
método <literal>Query.executeUpdate()</literal>:
</para>
<programlisting><![CDATA[Session session =
sessionFactory.openSession();
Modified:
core/trunk/documentation/manual/es-ES/src/main/docbook/content/collection_mapping.xml
===================================================================
---
core/trunk/documentation/manual/es-ES/src/main/docbook/content/collection_mapping.xml 2007-10-27
03:50:07 UTC (rev 14152)
+++
core/trunk/documentation/manual/es-ES/src/main/docbook/content/collection_mapping.xml 2007-10-27
12:53:39 UTC (rev 14153)
@@ -230,13 +230,20 @@
propiedad.
</para>
</callout>
- <callout arearefs="mappingcollection12">
+ <callout arearefs="mappingcollection13">
<para>
<literal>optimistic-lock</literal> (opcional - por
defecto a <literal>true</literal>):
Especifica que los cambios de estado de la colección
resultan en
incrementos de versión de la entidad dueña.
(Para asociaciones
uno a muchos, frecuentemente es razonable deshabilitar esta
opción.)
</para>
+ </callout>
+ <callout arearefs="mappingcollection14">
+ <para>
+ <literal>mutable</literal> (optional - defaults to
<literal>true</literal>):
+ A value of <literal>false</literal> specifies that the elements of the
+ collection never change (a minor performance optimization in some cases).
+ </para>
</callout>
</calloutlist>
</programlistingco>
@@ -555,7 +562,13 @@
<literal>entity-name</literal> (opcional): El nombre
de entidad de la clase
asociada, como una alternativa a
<literal>class</literal>.
</para>
- </callout>
+ </callout> <callout arearefs="manytomany8">
+ <para> UNTRANSLATED!
+ <literal>property-ref</literal>: (optional) The name of a property of
the associated
+ class that is joined to this foreign key. If not specified, the primary key of
+ the associated class is used.
+ </para>
+ </callout>
</calloutlist>
</programlistingco>
@@ -841,7 +854,7 @@
</class>
<class name="Item">
- <id name="id" column="ITEM_ID"/>
+ <id name="id" column="ITEM_ID"/>
...
<!-- inverse end -->
Modified:
core/trunk/documentation/manual/es-ES/src/main/docbook/content/configuration.xml
===================================================================
---
core/trunk/documentation/manual/es-ES/src/main/docbook/content/configuration.xml 2007-10-27
03:50:07 UTC (rev 14152)
+++
core/trunk/documentation/manual/es-ES/src/main/docbook/content/configuration.xml 2007-10-27
12:53:39 UTC (rev 14153)
@@ -392,11 +392,25 @@
</entry>
<entry>
Escribe todas las sentencias SQL a la consola.
- <para>
- <emphasis
role="strong">ej.</emphasis>
- <literal>true</literal> |
<literal>false</literal>
+ This is an alternative
+ to setting the log category <literal>org.hibernate.SQL</literal>
+ to <literal>debug</literal>.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
</para>
</entry>
+ </row> <row>
+ <entry>
+ <literal>hibernate.format_sql</literal>
+ </entry>
+ <entry>
+ Pretty print the SQL in the log and console.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>true</literal> | <literal>false</literal>
+ </para>
+ </entry>
</row>
<row>
<entry>
@@ -715,6 +729,13 @@
<emphasis
role="strong">ej.</emphasis>
<literal>on_close</literal> (por defecto)|
<literal>after_transaction</literal> |
<literal>after_statement</literal> |
<literal>auto</literal>
+ </para> <para>
+ Note that this setting only affects <literal>Session</literal>s returned
from
+ <literal>SessionFactory.openSession</literal>. For
<literal>Session</literal>s
+ obtained through <literal>SessionFactory.getCurrentSession</literal>,
the
+ <literal>CurrentSessionContext</literal> implementation configured for
use
+ controls the connection release mode for those
<literal>Session</literal>s.
+ See <xref linkend="architecture-current-session"/>
</para>
</entry>
</row>
@@ -928,7 +949,7 @@
<entry>
De habilitarse, la sesión será cerrada
automáticamente
durante la fase posterior a la compleción de la
transacción.
- (Muy útil cuando se usa Hibernate con CMT).
+ (Muy útil cuando se usa Hibernate con CMT).<xref
linkend="architecture-current-session"/>
<para>
<emphasis
role="strong">ej.</emphasis>
<literal>true</literal> |
<literal>false</literal>
@@ -950,7 +971,22 @@
<entry>Propósito</entry>
</row>
</thead>
- <tbody>
+ <tbody> <row>
+ <entry>
+ <literal>hibernate.current_session_context_class</literal>
+ </entry>
+ <entry>
+ Supply a (custom) strategy for the scoping of the "current"
+ <literal>Session</literal>. See
+ <xref linkend="architecture-current-session"/> for more
+ information about the built-in strategies.
+ <para>
+ <emphasis role="strong">eg.</emphasis>
+ <literal>jta</literal> | <literal>thread</literal> |
+ <literal>managed</literal> |
<literal>custom.Class</literal>
+ </para>
+ </entry>
+ </row>
<row>
<entry>
<literal>hibernate.query.factory_class</literal>
@@ -1636,7 +1672,10 @@
de arranque (o clase de utilidad) en tu aplicación, a menos
qie uses el despliegue
JMX con el <literal>HibernateService</literal> (discutido
luego).
</para>
-
+ <para> UNTRANSLATED!
+ If you use a JNDI <literal>SessionFactory</literal>, an EJB or any
other class may
+ obtain the <literal>SessionFactory</literal> using a JNDI lookup.
+ </para>
<para>
Si usas una <literal>SessionFactory</literal> de JNDI, un EJB
o cualquier otra
clase puede obtener la <literal>SessionFactory</literal>
usando una búsqueda
@@ -1651,36 +1690,27 @@
<sect2 id="configuration-j2ee-currentsession"
revision="1">
<title>Ligado automático de JTA y Session</title>
- <para>
- Para entornos no manejados hemos sugerido
<literal>HibernateUtil</literal> con una
- <literal>SessionFactory</literal> estática, y
administración de la
- <literal>Session</literal> de Hibernate. Este enfoque no es
fácil de usar
- en un entorno EJB, al poder ejecutarse muchos EJBs dentro de la misma
transacción
- pero no en la misma hebra. Recomendados que ligues la
<literal>SessionFactory</literal>
- a JNDI en un entorno manejado.
+ <para> UNTRANSLATED!
+ The easiest way to handle <literal>Session</literal>s and transactions
is
+ Hibernates automatic "current" <literal>Session</literal>
management.
+ See the discussion of <link
linkend="architecture-current-session">current sessions</link>.
+ Using the <literal>"jta"</literal> session context, if there
is no Hibernate
+ <literal>Session</literal> associated with the current JTA transaction,
one will
+ be started and associated with that JTA transaction the first time you call
+ <literal>sessionFactory.getCurrentSession()</literal>. The
<literal>Session</literal>s
+ retrieved via <literal>getCurrentSession()</literal> in
<literal>"jta"</literal> context
+ will be set to automatically flush before the transaction completes, close
+ after the transaction completes, and aggressively release JDBC connections
+ after each statement. This allows the <literal>Session</literal>s to
+ be managed by the life cycle of the JTA transaction to which it is associated,
+ keeping user code clean of such management concerns. Your code can either use
+ JTA programmatically through <literal>UserTransaction</literal>, or
(recommended
+ for portable code) use the Hibernate <literal>Transaction</literal> API
to set
+ transaction boundaries. If you run in an EJB container, declarative transaction
+ demarcation with CMT is preferred.
</para>
- <para>
- En vez de rodar tu propia utilidad de
<literal>ThreadLocal</literal>,
- usa el método
<literal>getCurrentSession()</literal> en la
- <literal>SessionFactory</literal> para obtener una
<literal>Session</literal>
- de Hibernate. Si no hubiese una <literal>Session</literal> de
Hibernate en la
- transacción JTA actual, se arrancará y
asignará una.
- Ambas opciones de configuración
<literal>hibernate.transaction.flush_before_completion</literal>
- y
<literal>hibernate.transaction.auto_close_session</literal>, serán
establecidas
- automáticamente para cada
<literal>Session</literal> que obtengas con
- <literal>getCurrentSession()</literal>, de modo que
éstas serán
- limpiadas (flushed) y cerradas automáticamente cuando el
contenedor complete
- las transacciones JTA.
- </para>
- <para>
- Si tu, por ejemplo, usas el patrón de diseño DAO
para escribir tu
- capa de persistencia, todos los DAO's buscan la
<literal>SessionFactory</literal>
- cuando se necesite y abren la sesión "actual". No
hay necesidad de pasar
- las instancias de <literal>SessionFactory</literal> o
<literal>Session</literal>
- alrededor entre el código de control y el código
DAO.
- </para>
</sect2>
Modified: core/trunk/documentation/manual/es-ES/src/main/docbook/content/events.xml
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/events.xml 2007-10-27
03:50:07 UTC (rev 14152)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/events.xml 2007-10-27
12:53:39 UTC (rev 14153)
@@ -22,7 +22,10 @@
creado y actualiza la propiedad
<literal>lastUpdateTimestamp</literal> cuando un
<literal>Auditable</literal> es acutalizado.
</para>
-
+ <para> UNTRANSLATED!
+ You may either implement <literal>Interceptor</literal> directly or
(better) extend
+ <literal>EmptyInterceptor</literal>.
+ </para>
<programlisting><![CDATA[package org.hibernate.test;
import java.io.Serializable;
@@ -103,14 +106,24 @@
}]]></programlisting>
- <para>
- El interceptor podría ser especificado cuando se crea la
sesión:
+ <para> UNTRANSLATED!
+ Interceptors come in two flavors: <literal>Session</literal>-scoped
and
+ <literal>SessionFactory</literal>-scoped.
+ </para>
+
+ <para> UNTRANSLATED!
+ A <literal>Session</literal>-scoped interceptor is specified
+ when a session is opened using one of the overloaded SessionFactory.openSession()
+ methods accepting an <literal>Interceptor</literal>.
</para>
-
<programlisting><![CDATA[Session session = sf.openSession( new
AuditInterceptor() );]]></programlisting>
-
- <para>
- Puedes además establecer un interceptor a un nivel global, usando
la <literal>Configuration</literal>:
+ <para> UNTRANSLATED!
+ A <literal>SessionFactory</literal>-scoped interceptor is registered with
the <literal>Configuration</literal>
+ object prior to building the <literal>SessionFactory</literal>. In this
case, the supplied interceptor
+ will be applied to all sessions opened from that
<literal>SessionFactory</literal>; this is true unless
+ a session is opened explicitly specifying the interceptor to use.
<literal>SessionFactory</literal>-scoped
+ interceptors must be thread safe, taking care to not store session-specific state since
multiple
+ sessions will use this interceptor (potentially) concurrently.
</para>
<programlisting><![CDATA[new Configuration().setInterceptor( new
AuditInterceptor() );]]></programlisting>
@@ -218,7 +231,11 @@
<listener type="pre-update"
class="org.hibernate.secure.JACCPreUpdateEventListener"/>
<listener type="pre-insert"
class="org.hibernate.secure.JACCPreInsertEventListener"/>
<listener type="pre-load"
class="org.hibernate.secure.JACCPreLoadEventListener"/>]]></programlisting>
-
+<para> UNTRANSLATED!
+ Note that <literal><listener type="..."
class="..."/></literal> is just a shorthand
+ for <literal><event type="..."><listener
class="..."/></event></literal>
+ when there is exactly one listener for a particular event type.
+ </para>
<para>
Seguido, aún en <literal>hibernate.cfg.xml</literal>,
liga los permisos a roles:
</para>
Modified:
core/trunk/documentation/manual/es-ES/src/main/docbook/content/inheritance_mapping.xml
===================================================================
---
core/trunk/documentation/manual/es-ES/src/main/docbook/content/inheritance_mapping.xml 2007-10-27
03:50:07 UTC (rev 14152)
+++
core/trunk/documentation/manual/es-ES/src/main/docbook/content/inheritance_mapping.xml 2007-10-27
12:53:39 UTC (rev 14153)
@@ -42,6 +42,24 @@
</listitem>
</itemizedlist>
+
+ <para> UNTRANSLATED!
+ It is possible to define <literal>subclass</literal>,
<literal>union-subclass</literal>,
+ and <literal>joined-subclass</literal> mappings in separate mapping
documents, directly beneath
+ <literal>hibernate-mapping</literal>. This allows you to extend a class
hierachy just by adding
+ a new mapping file. You must specify an <literal>extends</literal>
attribute in the subclass mapping,
+ naming a previously mapped superclass. Note: Previously this feature made the ordering
of the mapping
+ documents important. Since Hibernate3, the ordering of mapping files does not matter
when using the
+ extends keyword. The ordering inside a single mapping file still needs to be defined as
superclasses
+ before subclasses.
+ </para>
+
+ <programlisting><![CDATA[
+ <hibernate-mapping>
+ <subclass name="DomesticCat" extends="Cat"
discriminator-value="D">
+ <property name="name" type="string"/>
+ </subclass>
+ </hibernate-mapping>]]></programlisting>
<para>
Es posible usar estrategias de mapeo diferentes para diferentes
ramificaciones de la misma jerarquía de herencia, y entonces usar
@@ -258,7 +276,12 @@
de unión de subclase, de hecho la semilla de clave primaria tiene
que ser
compartida a través de todas las subclases unidas de una
jerarquía.
</para>
-
+ <para> UNTRANSLATED!
+ If your superclass is abstract, map it with
<literal>abstract="true"</literal>.
+ Of course, if it is not abstract, an additional table (defaults to
+ <literal>PAYMENT</literal> in the example above) is needed to hold
instances
+ of the superclass.
+ </para>
</sect2>
<sect2 id="inheritance-tableperconcreate-polymorphism">
Modified: core/trunk/documentation/manual/es-ES/src/main/docbook/content/performance.xml
===================================================================
---
core/trunk/documentation/manual/es-ES/src/main/docbook/content/performance.xml 2007-10-27
03:50:07 UTC (rev 14152)
+++
core/trunk/documentation/manual/es-ES/src/main/docbook/content/performance.xml 2007-10-27
12:53:39 UTC (rev 14153)
@@ -68,6 +68,20 @@
<emphasis>Recuperación perezosa de
colecciones</emphasis> - se recupera una colección cuando la
aplicación invoca una operación sobre la
colección. (Esto es por defecto para las colecciones.)
</para>
+ </listitem> <listitem>
+ <para>
+ <emphasis>"Extra-lazy" collection fetching</emphasis> -
individual
+ elements of the collection are accessed from the database as needed.
+ Hibernate tries not to fetch the whole collection into memory unless
+ absolutely needed (suitable for very large collections)
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <emphasis>Proxy fetching</emphasis> - a single-valued association is
+ fetched when a method other than the identifier getter is invoked
+ upon the associated object.
+ </para>
</listitem>
<listitem>
<para>
@@ -186,9 +200,17 @@
<para>
las consultas de <literal>Criteria</literal>
</para>
+ </listitem> <listitem>
+ <para>
+ HQL queries if <literal>subselect</literal> fetching is used
+ </para>
</listitem>
</itemizedlist>
-
+ <para>
+ No matter what fetching strategy you use, the defined non-lazy graph is guaranteed
+ to be loaded into memory. Note that this might result in several immediate selects
+ being used to execute a particular HQL query.
+ </para>
<para>
Usualmente, no usamos el documento de mapeo para personalizar la
recuperación. En cambio, mantenemos el
comportamiento por defecto, y lo sobrescribimos para una
transacción en particular, usando
@@ -353,7 +375,12 @@
Hibernate detectará las clase persistentes que sobrescriban
<literal>equals()</literal> o
<literal>hashCode()</literal>.
</para>
-
+ <para> UNTRANSLATED!!!
+ By choosing <literal>lazy="no-proxy"</literal> instead of the
default
+ <literal>lazy="proxy"</literal>, we can avoid the problems
associated with typecasting.
+ However, we will require buildtime bytecode instrumentation, and all operations
+ will result in immediate proxy initialization.
+ </para>
</sect2>
<sect2 id="performance-fetching-initialization">
@@ -673,7 +700,8 @@
<programlistingco>
<areaspec>
- <area id="cache1" coords="2 70"/>
+ <area id="cache1" coords="2 70"/><area
id="cache2" coords="3 70"/>
+ <area id="cache3" coords="4 70"/>
</areaspec>
<programlisting><![CDATA[<cache
usage="transactional|read-write|nonstrict-read-write|read-only"
@@ -687,7 +715,21 @@
<literal>nonstrict-read-write</literal> o
<literal>read-only</literal>
</para>
- </callout>
+ </callout> <callout arearefs="cache2">
+ <para>
+ <literal>region</literal> (optional, defaults to the class or
+ collection role name) specifies the name of the second level cache
+ region
+ </para>
+ </callout>
+ <callout arearefs="cache3">
+ <para>
+ <literal>include</literal> (optional, defaults to
<literal>all</literal>)
+ <literal>non-lazy</literal> specifies that properties of the entity
mapped
+ with <literal>lazy="true"</literal> may not be cached when
attribute-level
+ lazy fetching is enabled
+ </para>
+ </callout>
</calloutlist>
</programlistingco>
Modified:
core/trunk/documentation/manual/es-ES/src/main/docbook/content/persistent_classes.xml
===================================================================
---
core/trunk/documentation/manual/es-ES/src/main/docbook/content/persistent_classes.xml 2007-10-27
03:50:07 UTC (rev 14152)
+++
core/trunk/documentation/manual/es-ES/src/main/docbook/content/persistent_classes.xml 2007-10-27
12:53:39 UTC (rev 14153)
@@ -471,6 +471,71 @@
</para>
</sect1>
+ <sect1 id="persistent-classes-tuplizers" revision="1">
+ <title>UNTRANSLATED!!! Tuplizers</title>
+
+ <para>
+ <literal>org.hibernate.tuple.Tuplizer</literal>, and its
sub-interfaces, are responsible
+ for managing a particular representation of a piece of data, given that
representation's
+ <literal>org.hibernate.EntityMode</literal>. If a given piece of data
is thought of as
+ a data structure, then a tuplizer is the thing which knows how to create such a
data structure
+ and how to extract values from and inject values into such a data structure. For
example,
+ for the POJO entity mode, the correpsonding tuplizer knows how create the POJO
through its
+ constructor and how to access the POJO properties using the defined property
accessors.
+ There are two high-level types of Tuplizers, represented by the
+ <literal>org.hibernate.tuple.entity.EntityTuplizer</literal> and
<literal>org.hibernate.tuple.component.ComponentTuplizer</literal>
+ interfaces. <literal>EntityTuplizer</literal>s are responsible for
managing the above mentioned
+ contracts in regards to entities, while
<literal>ComponentTuplizer</literal>s do the same for
+ components.
+ </para>
+
+ <para>
+ Users may also plug in their own tuplizers. Perhaps you require that a
<literal>java.util.Map</literal>
+ implementation other than <literal>java.util.HashMap</literal> be used
while in the
+ dynamic-map entity-mode; or perhaps you need to define a different proxy generation
strategy
+ than the one used by default. Both would be achieved by defining a custom
tuplizer
+ implementation. Tuplizers definitions are attached to the entity or component
mapping they
+ are meant to manage. Going back to the example of our customer entity:
+ </para>
+
+ <programlisting><![CDATA[<hibernate-mapping>
+ <class entity-name="Customer">
+ <!--
+ Override the dynamic-map entity-mode
+ tuplizer for the customer entity
+ -->
+ <tuplizer entity-mode="dynamic-map"
+ class="CustomMapTuplizerImpl"/>
+
+ <id name="id" type="long" column="ID">
+ <generator class="sequence"/>
+ </id>
+
+ <!-- other properties -->
+ ...
+ </class>
+ </hibernate-mapping>
+
+
+ public class CustomMapTuplizerImpl
+ extends org.hibernate.tuple.entity.DynamicMapEntityTuplizer {
+ // override the buildInstantiator() method to plug in our custom map...
+ protected final Instantiator buildInstantiator(
+ org.hibernate.mapping.PersistentClass mappingInfo) {
+ return new CustomMapInstantiator( mappingInfo );
+ }
+
+ private static final class CustomMapInstantiator
+ extends org.hibernate.tuple.DynamicMapInstantitor {
+ // override the generateMap() method to return our custom map...
+ protected final Map generateMap() {
+ return new CustomMap();
+ }
+ }
+ }]]></programlisting>
+
+
+ </sect1>
<para>
PORHACER: Documentar el framework de extensiones del usuario en los paquetes
Modified: core/trunk/documentation/manual/es-ES/src/main/docbook/content/query_hql.xml
===================================================================
---
core/trunk/documentation/manual/es-ES/src/main/docbook/content/query_hql.xml 2007-10-27
03:50:07 UTC (rev 14152)
+++
core/trunk/documentation/manual/es-ES/src/main/docbook/content/query_hql.xml 2007-10-27
12:53:39 UTC (rev 14153)
@@ -182,6 +182,65 @@
<programlisting><![CDATA[from Document doc fetch all properties where
lower(doc.name) like '%cats%']]></programlisting>
</sect1>
+
+ <sect1 id="queryhql-joins-forms">
+ <title>UNTRANSLATED!!! Forms of join syntax</title>
+
+ <para>
+ HQL supports two forms of association joining:
<literal>implicit</literal> and <literal>explicit</literal>.
+ </para>
+
+ <para>
+ The queries shown in the previous section all use the
<literal>explicit</literal> form where
+ the join keyword is explicitly used in the from clause. This is the recommended
form.
+ </para>
+
+ <para>
+ The <literal>implicit</literal> form does not use the join keyword.
Instead, the
+ associations are "dereferenced" using dot-notation.
<literal>implicit</literal> joins
+ can appear in any of the HQL clauses. <literal>implicit</literal> join
result
+ in inner joins in the resulting SQL statement.
+ </para>
+
+ <programlisting><![CDATA[from Cat as cat where cat.mate.name like
'%s%']]></programlisting>
+ </sect1>
+
+ <sect1 id="queryhql-identifier-property">
+ <title>Refering to identifier property</title>
+
+ <para>
+ There are, generally speaking, 2 ways to refer to an entity's identifier
property:
+ </para>
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para>
+ The special property (lowercase) <literal>id</literal> may be used to
reference the identifier
+ property of an entity <emphasis>provided that entity does not define a
non-identifier property
+ named id</emphasis>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If the entity defines a named identifier property, you may use that property
name.
+ </para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ References to composite identifier properties follow the same naming rules. If
the
+ entity has a non-identifier property named id, the composite identifier property
can only
+ be referenced by its defined named; otherwise, the special
<literal>id</literal> property
+ can be used to rerference the identifier property.
+ </para>
+
+ <para>
+ Note: this has changed significantly starting in version 3.2.2. In previous
versions,
+ <literal>id</literal> <emphasis>always</emphasis> referred
to the identifier property no
+ matter what its actual name. A ramification of that decision was that
non-identifier
+ properties named <literal>id</literal> could never be referenced in
Hibernate queries.
+ </para>
+ </sect1>
+
<sect1 id="queryhql-select">
<title>La cláusula select</title>
@@ -843,56 +902,38 @@
SQL). Incluso se permiten subconsultas correlacionadas (subconsultas que
hacen referencia a un alias en la
consulta exterior).
</para>
-
- <programlisting><![CDATA[from Cat as fatcat
-where fatcat.weight > (
- select avg(cat.weight) from DomesticCat cat
-)]]></programlisting>
-
- <programlisting><![CDATA[from DomesticCat as cat
-where cat.name = some (
- select name.nickName from Name as name
-)]]></programlisting>
-
- <programlisting><![CDATA[from Cat as cat
-where not exists (
- from Cat as mate where mate.mate = cat
-)]]></programlisting>
-
- <programlisting><![CDATA[from DomesticCat as cat
-where cat.name not in (
- select name.nickName from Name as name
-)]]></programlisting>
-
- <para>
- Para las subconsultas con más de una expresión en la
lista de selección, puedes usar un constructor
- de tuplas:
- </para>
-
- <programlisting><![CDATA[from Cat as cat
-where not ( cat.name, cat.color ) in (
- select cat.name, cat.color from DomesticCat cat
-)]]></programlisting>
-
- <para>
- Nota que en algunas bases de datos (pero no en Oracle o HSQL), puedes usar
constructores de tuplar en
- otros contextos, por ejemplo al consultar componentes o tipos de usuario
compuestos:
- </para>
-
- <programlisting><![CDATA[from Person where name = ('Gavin',
'A', 'King')]]></programlisting>
-
- <para>
- Que es equivalente a la más verborrágica:
- </para>
-
- <programlisting><![CDATA[from Person where name.first = 'Gavin'
and name.initial = 'A' and name.last =
'King')]]></programlisting>
-
- <para>
- Existen dos buenas razones por las cuales podrías no querer hacer
este tipo de cosa: primero, no es
- completamente portable entre plataformas de base de datos; segundo, la
consulta ahora es dependiente
- del orden de propiedades en el documento de mapeo.
- </para>
-
+
+ <programlisting><![CDATA[from Cat as fatcat
+ where fatcat.weight > (
+ select avg(cat.weight) from DomesticCat cat
+ )]]></programlisting>
+
+ <programlisting><![CDATA[from DomesticCat as cat
+ where cat.name = some (
+ select name.nickName from Name as name
+ )]]></programlisting>
+
+ <programlisting><![CDATA[from Cat as cat
+ where not exists (
+ from Cat as mate where mate.mate = cat
+ )]]></programlisting>
+
+ <programlisting><![CDATA[from DomesticCat as cat
+ where cat.name not in (
+ select name.nickName from Name as name
+ )]]></programlisting>
+
+ <programlisting><![CDATA[select cat.id, (select max(kit.weight) from cat.kitten
kit)
+ from Cat as cat]]></programlisting>
+
+ <para>
+ Note that HQL subqueries may occur only in the select or where clauses.
+ </para>
+
+ <para>
+ Note that subqueries can also utilize <literal>row value
constructor</literal> syntax. See
+ <xref linkend="queryhql-tuple"/> for more details.
+ </para>
</sect1>
<sect1 id="queryhql-examples">
Modified: core/trunk/documentation/manual/es-ES/src/main/docbook/content/query_sql.xml
===================================================================
---
core/trunk/documentation/manual/es-ES/src/main/docbook/content/query_sql.xml 2007-10-27
03:50:07 UTC (rev 14152)
+++
core/trunk/documentation/manual/es-ES/src/main/docbook/content/query_sql.xml 2007-10-27
12:53:39 UTC (rev 14153)
@@ -15,98 +15,388 @@
Hibernate3 te permite especificar SQL escrito a mano (incluyendo procedimientos
almacenados) para todas
las operaciones de creación, actualización, borrado y
carga.
</para>
-
- <sect1 id="querysql-creating">
- <title>Creando una <literal>Query</literal> de SQL
nativo</title>
-
- <para>
- Las consultas SQL se controlan por medio de la interface
<literal>SQLQuery</literal>, que se obtiene
- llamando a <literal>Session.createSQLQuery()</literal>.
- </para>
-
- <programlisting><![CDATA[List cats = sess.createSQLQuery("select
{cat.*} from cats cat")
- .addEntity("cat", Cat.class)
- .setMaxResults(50)
- .list();]]></programlisting>
-
- <para>
- Esta consulta especificada:
- </para>
-
- <itemizedlist>
- <listitem>
- <para>
- la cadena de consulta SQL, con un lugar para que Hibernate inyecte los alias
de columnas
- </para>
- </listitem>
- <listitem>
- <para>
- la entidad devuelta por la consulta, y sus alias de tablas SQL
- </para>
- </listitem>
- </itemizedlist>
- <para>
- El método <literal>addEntity()</literal> asocia alias
de tablas SQL con clases de entidad,
- y determina la forma del conjunto resultado de la consulta.
- </para>
-
- <para>
- El método <literal>addJoin()</literal> puede ser usado
para cargar asociaciones a otras entidades y
- colecciones.
- </para>
-
- <programlisting><![CDATA[List cats = sess.createSQLQuery(
- "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother =
cat.id"
- )
- .addEntity("cat", Cat.class)
- .addJoin("kitten", "cat.kittens")
- .list();]]></programlisting>
-
- <para>
- Una consulta SQL nativa podría devolver un valor escalar simple o
una combinación de escalares y entidades.
- </para>
-
- <programlisting><![CDATA[Double max = (Double)
sess.createSQLQuery("select max(cat.weight) as maxWeight from cats cat")
- .addScalar("maxWeight", Hibernate.DOUBLE);
- .uniqueResult();]]></programlisting>
-
-
+ <sect1 id="querysql-creating" revision="4">
+ <title>Using a <literal>SQLQuery</literal></title>
+
+ <para>Execution of native SQL queries is controlled via the
+ <literal>SQLQuery</literal> interface, which is obtained by calling
+ <literal>Session.createSQLQuery()</literal>. The following describes
how
+ to use this API for querying.</para>
+
+ <sect2>
+ <title>Scalar queries</title>
+
+ <para>The most basic SQL query is to get a list of scalars
+ (values).</para>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM
CATS").list();
+ sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").list();
+ ]]></programlisting>
+
+ <para>These will both return a List of Object arrays (Object[]) with
+ scalar values for each column in the CATS table. Hibernate will use
+ ResultSetMetadata to deduce the actual order and types of the returned
+ scalar values.</para>
+
+ <para>To avoid the overhead of using
+ <literal>ResultSetMetadata</literal> or simply to be more explicit in
+ what is returned one can use
<literal>addScalar()</literal>.</para>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM
CATS")
+ .addScalar("ID", Hibernate.LONG)
+ .addScalar("NAME", Hibernate.STRING)
+ .addScalar("BIRTHDATE", Hibernate.DATE)
+ ]]></programlisting>
+
+ <para>This query specified:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>the SQL query string</para>
+ </listitem>
+
+ <listitem>
+ <para>the columns and types to return</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>This will still return Object arrays, but now it will not use
+ <literal>ResultSetMetdata</literal> but will instead explicitly get
the
+ ID, NAME and BIRTHDATE column as respectively a Long, String and a Short
+ from the underlying resultset. This also means that only these three
+ columns will be returned, even though the query is using
+ <literal>*</literal> and could return more than the three listed
+ columns.</para>
+
+ <para>It is possible to leave out the type information for all or some
+ of the scalars.</para>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM
CATS")
+ .addScalar("ID", Hibernate.LONG)
+ .addScalar("NAME")
+ .addScalar("BIRTHDATE")
+ ]]></programlisting>
+
+ <para>This is essentially the same query as before, but now
+ <literal>ResultSetMetaData</literal> is used to decide the type of
NAME
+ and BIRTHDATE where as the type of ID is explicitly specified.</para>
+
+ <para>How the java.sql.Types returned from ResultSetMetaData is mapped
+ to Hibernate types is controlled by the Dialect. If a specific type is
+ not mapped or does not result in the expected type it is possible to
+ customize it via calls to <literal>registerHibernateType</literal> in
+ the Dialect.</para>
+ </sect2>
+
+ <sect2>
+ <title>Entity queries</title>
+
+ <para>The above queries were all about returning scalar values,
+ basically returning the "raw" values from the resultset. The following
+ shows how to get entity objects from a native sql query via
+ <literal>addEntity()</literal>.</para>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT * FROM
CATS").addEntity(Cat.class);
+ sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM
CATS").addEntity(Cat.class);
+ ]]></programlisting>
+
+ <para>This query specified:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>the SQL query string</para>
+ </listitem>
+
+ <listitem>
+ <para>the entity returned by the query</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Assuming that Cat is mapped as a class with the columns ID, NAME
+ and BIRTHDATE the above queries will both return a List where each
+ element is a Cat entity.</para>
+
+ <para>If the entity is mapped with a
<literal>many-to-one</literal> to
+ another entity it is required to also return this when performing the
+ native query, otherwise a database specific "column not found" error
+ will occur. The additional columns will automatically be returned when
+ using the * notation, but we prefer to be explicit as in the following
+ example for a <literal>many-to-one</literal> to a
+ <literal>Dog</literal>:</para>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME,
BIRTHDATE, DOG_ID FROM CATS").addEntity(Cat.class);
+ ]]></programlisting>
+
+ <para>This will allow cat.getDog() to function properly.</para>
+ </sect2>
+
+ <sect2>
+ <title>Handling associations and collections</title>
+
+ <para>It is possible to eagerly join in the
<literal>Dog</literal> to
+ avoid the possible extra roundtrip for initializing the proxy. This is
+ done via the <literal>addJoin()</literal> method, which allows you to
+ join in an association or collection.</para>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT c.ID, NAME,
BIRTHDATE, DOG_ID, D_ID, D_NAME FROM CATS c, DOGS d WHERE c.DOG_ID = d.D_ID")
+ .addEntity("cat", Cat.class)
+ .addJoin("cat.dog");
+ ]]></programlisting>
+
+ <para>In this example the returned <literal>Cat</literal>'s
will have
+ their <literal>dog</literal> property fully initialized without any
+ extra roundtrip to the database. Notice that we added a alias name
+ ("cat") to be able to specify the target property path of the join. It
+ is possible to do the same eager joining for collections, e.g. if the
+ <literal>Cat</literal> had a one-to-many to
<literal>Dog</literal>
+ instead.</para>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT ID, NAME,
BIRTHDATE, D_ID, D_NAME, CAT_ID FROM CATS c, DOGS d WHERE c.ID = d.CAT_ID")
+ .addEntity("cat", Cat.class)
+ .addJoin("cat.dogs");
+ ]]></programlisting>
+
+ <para>
+ At this stage we are reaching the limits of what is possible with native queries
without starting to
+ enhance the sql queries to make them usable in Hibernate; the problems starts to
arise when returning
+ multiple entities of the same type or when the default alias/column names are not
enough.
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>Returning multiple entities</title>
+
+ <para>Until now the result set column names are assumed to be the same
+ as the column names specified in the mapping document. This can be
+ problematic for SQL queries which join multiple tables, since the same
+ column names may appear in more than one table.</para>
+
+ <para>Column alias injection is needed in the following query (which
+ most likely will fail):</para>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT c.*, m.* FROM
CATS c, CATS m WHERE c.MOTHER_ID = c.ID")
+ .addEntity("cat", Cat.class)
+ .addEntity("mother", Cat.class)
+ ]]></programlisting>
+
+ <para>The intention for this query is to return two Cat instances per
+ row, a cat and its mother. This will fail since there is a conflict of
+ names since they are mapped to the same column names and on some
+ databases the returned column aliases will most likely be on the form
+ "c.ID", "c.NAME", etc. which are not equal to the columns
specificed in
+ the mappings ("ID" and "NAME").</para>
+
+ <para>The following form is not vulnerable to column name
+ duplication:</para>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT {cat.*},
{mother.*} FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID")
+ .addEntity("cat", Cat.class)
+ .addEntity("mother", Cat.class)
+ ]]></programlisting>
+
+ <para>This query specified:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>the SQL query string, with placeholders for Hibernate to
+ inject column aliases</para>
+ </listitem>
+
+ <listitem>
+ <para>the entities returned by the query</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>The {cat.*} and {mother.*} notation used above is a shorthand for
+ "all properties". Alternatively, you may list the columns explicity,
but
+ even in this case we let Hibernate inject the SQL column aliases for
+ each property. The placeholder for a column alias is just the property
+ name qualified by the table alias. In the following example, we retrieve
+ Cats and their mothers from a different table (cat_log) to the one
+ declared in the mapping metadata. Notice that we may even use the
+ property aliases in the where clause if we like.</para>
+
+ <programlisting><![CDATA[String sql = "SELECT ID as {c.id}, NAME as
{c.name}, " +
+ "BIRTHDATE as {c.birthDate}, MOTHER_ID as {c.mother}, {mother.*} " +
+ "FROM CAT_LOG c, CAT_LOG m WHERE {c.mother} = c.ID";
+
+ List loggedCats = sess.createSQLQuery(sql)
+ .addEntity("cat", Cat.class)
+ .addEntity("mother", Cat.class).list()
+ ]]></programlisting>
+
+ <sect3 id="querysql-aliasreferences" revision="2">
+ <title>Alias and property references</title>
+
+ <para>For most cases the above alias injection is needed, but for
+ queries relating to more complex mappings like composite properties,
+ inheritance discriminators, collections etc. there are some specific
+ aliases to use to allow Hibernate to inject the proper aliases.</para>
+
+ <para>The following table shows the different possibilities of using
+ the alias injection. Note: the alias names in the result are examples,
+ each alias will have a unique and probably different name when
+ used.</para>
+
+ <table frame="topbot" id="aliasinjection-summary">
+ <title>Alias injection names</title>
+
+ <tgroup cols="3">
+ <colspec colwidth="1*" />
+
+ <colspec colwidth="1*" />
+
+ <colspec colwidth="2.5*" />
+
+ <thead>
+ <row>
+ <entry>Description</entry>
+
+ <entry>Syntax</entry>
+
+ <entry>Example</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry>A simple property</entry>
+
+
<entry><literal>{[aliasname].[propertyname]</literal></entry>
+
+ <entry><literal>A_NAME as
{item.name}</literal></entry>
+ </row>
+
+ <row>
+ <entry>A composite property</entry>
+
+
<entry><literal>{[aliasname].[componentname].[propertyname]}</literal></entry>
+
+ <entry><literal>CURRENCY as {item.amount.currency}, VALUE as
+ {item.amount.value}</literal></entry>
+ </row>
+
+ <row>
+ <entry>Discriminator of an entity</entry>
+
+ <entry><literal>{[aliasname].class}</literal></entry>
+
+ <entry><literal>DISC as
{item.class}</literal></entry>
+ </row>
+
+ <row>
+ <entry>All properties of an entity</entry>
+
+ <entry><literal>{[aliasname].*}</literal></entry>
+
+ <entry><literal>{item.*}</literal></entry>
+ </row>
+
+ <row>
+ <entry>A collection key</entry>
+
+ <entry><literal>{[aliasname].key}</literal></entry>
+
+ <entry><literal>ORGID as {coll.key}</literal></entry>
+ </row>
+
+ <row>
+ <entry>The id of an collection</entry>
+
+ <entry><literal>{[aliasname].id}</literal></entry>
+
+ <entry><literal>EMPID as {coll.id}</literal></entry>
+ </row>
+
+ <row>
+ <entry>The element of an collection</entry>
+
+
<entry><literal>{[aliasname].element}</literal></entry>
+
+ <entry><literal>XID as
{coll.element}</literal></entry>
+ </row>
+
+ <row>
+ <entry>roperty of the element in the collection</entry>
+
+
<entry><literal>{[aliasname].element.[propertyname]}</literal></entry>
+
+ <entry><literal>NAME as
{coll.element.name}</literal></entry>
+ </row>
+
+ <row>
+ <entry>All properties of the element in the collection</entry>
+
+
<entry><literal>{[aliasname].element.*}</literal></entry>
+
+ <entry><literal>{coll.element.*}</literal></entry>
+ </row>
+
+ <row>
+ <entry>All properties of the the collection</entry>
+
+ <entry><literal>{[aliasname].*}</literal></entry>
+
+ <entry><literal>{coll.*}</literal></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect3>
+ </sect2>
+
+ <sect2>
+ <title>Returning non-managed entities</title>
+
+ <para>It is possible to apply a ResultTransformer to native sql queries.
Allowing it to e.g. return non-managed entities.</para>
+
+ <programlisting><![CDATA[sess.createSQLQuery("SELECT NAME, BIRTHDATE
FROM CATS")
+
.setResultTransformer(Transformers.aliasToBean(CatDTO.class))]]></programlisting>
+
+ <para>This query specified:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>the SQL query string</para>
+ </listitem>
+
+ <listitem>
+ <para>a result transformer</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ The above query will return a list of <literal>CatDTO</literal> which
has been instantiated and injected the values of NAME and BIRTHNAME into its
corresponding
+ properties or fields.
+ </para>
+ </sect2>
+
+ <sect2>
+ <title>Handling inheritance</title>
+
+ <para>Native sql queries which query for entities that is mapped as part
+ of an inheritance must include all properties for the baseclass and all
+ it subclasses.</para>
+ </sect2>
+
+ <sect2>
+ <title>Parameters</title>
+
+ <para>Native sql queries support positional as well as named
+ parameters:</para>
+
+ <programlisting><![CDATA[Query query = sess.createSQLQuery("SELECT *
FROM CATS WHERE NAME like ?").addEntity(Cat.class);
+ List pusList = query.setString(0, "Pus%").list();
+
+ query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like
:name").addEntity(Cat.class);
+ List pusList = query.setString("name", "Pus%").list();
]]></programlisting>
+ </sect2>
+
+
+
</sect1>
-
- <sect1 id="querysql-aliasreferences">
- <title>Alias y referencias de propiedad</title>
-
- <para>
- La notación <literal>{cat.*}</literal> usada arriba es
un atajo para "todas las propiedades".
- Alternativamente, puedes listar las columnas explícitamente, pero
incluso en este caso dejamos
- que Hibernate inyecte los alias de columnas SQL para cada propiedad. El lugar
para un alias de columna
- es sólo el nombre de propiedad cualificado por el alias de la
tabla. En el siguiente ejemplo,
- recuperamos <literal>Cat</literal>s de una tabla diferente
(<literal>cat_log</literal>) a una
- declarada en los metadatos de mapeo. Nota que podríamos incluso
usar los alias de propiedad en la
- cláusula where si quisieramos.
- </para>
- <para>
- La sintáxis <literal>{}</literal>
<emphasis>no</emphasis> es requerida para consultas con nombre.
- Ver <xref linkend="querysql-namedqueries"/>
- </para>
-
- <programlisting><![CDATA[String sql = "select cat.originalId as
{cat.id}, " +
- "cat.mateid as {cat.mate}, cat.sex as {cat.sex}, " +
- "cat.weight*10 as {cat.weight}, cat.name as {cat.name} " +
- "from cat_log cat where {cat.mate} = :catId"
-List loggedCats = sess.createSQLQuery(sql)
- .addEntity("cat", Cat.class)
- .setLong("catId", catId)
- .list();]]></programlisting>
-
- <para>
- <emphasis>Nota:</emphasis> si listas cada propiedad
explícitamente, ¡debes incluir todas las
- propiedades de la clase <emphasis>y sus subclases</emphasis>!
- </para>
-
- </sect1>
<sect1 id="querysql-namedqueries" revision="2">
<title>Consultas SQL con nombre</title>
@@ -164,7 +454,38 @@
p.AGE AS age,
FROM PERSON p WHERE p.NAME LIKE 'Hiber%'
</sql-query>]]></programlisting>
+<para>You can externalize the resultset mapping informations in a
+ <literal><resultset></literal> element to either reuse them
accross
+ several named queries or through the
+ <literal>setResultSetMapping()</literal> API.</para>
+<programlisting><![CDATA[<resultset name="personAddress">
+ <return alias="person" class="eg.Person"/>
+ <return-join alias="address"
property="person.mailingAddress"/>
+ </resultset>
+
+ <sql-query name="personsWith" resultset-ref="personAddress">
+ SELECT person.NAME AS {person.name},
+ person.AGE AS {person.age},
+ person.SEX AS {person.sex},
+ address.STREET AS {address.street},
+ address.CITY AS {address.city},
+ address.STATE AS {address.state},
+ address.ZIP AS {address.zip}
+ FROM PERSON person
+ JOIN ADDRESS address
+ ON person.ID = address.PERSON_ID AND address.TYPE='MAILING'
+ WHERE person.NAME LIKE :namePattern
+ </sql-query>]]></programlisting>
+
+<para>You can alternatively use the resultset mapping information in your
+ hbm files directly in java code.</para>
+
+<programlisting><![CDATA[List cats = sess.createSQLQuery(
+ "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother
= cat.id"
+ )
+ .setResultSetMapping("catAndKitten")
+ .list();]]></programlisting>
<sect2 id="propertyresults">
<title>Usando return-property para especificar
explícitamente nombres de columna/alias</title>
Modified: core/trunk/documentation/manual/es-ES/src/main/docbook/content/session_api.xml
===================================================================
---
core/trunk/documentation/manual/es-ES/src/main/docbook/content/session_api.xml 2007-10-27
03:50:07 UTC (rev 14152)
+++
core/trunk/documentation/manual/es-ES/src/main/docbook/content/session_api.xml 2007-10-27
12:53:39 UTC (rev 14153)
@@ -101,7 +101,28 @@
usar <literal>persist()</literal> en vez de
<literal>save()</literal>, con la semántica
definida en el temprano borrador de EJB3.
</para>
-
+ <itemizedlist spacing="compact">
+ <listitem>
+ <para> UNTRANSLATED!!!
+ <literal>persist()</literal> makes a transient instance persistent.
+ However, it doesn't guarantee that the identifier value will be assigned to
+ the persistent instance immediately, the assignment might happen at flush time.
+ <literal>persist()</literal> also guarantees that it will not execute an
+ <literal>INSERT</literal> statement if it is called outside of
transaction
+ boundaries. This is useful in long-running conversations with an extended
+ Session/persistence context.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ <literal>save()</literal> does guarantee to return an identifier. If an
INSERT
+ has to be executed to get the identifier ( e.g. "identity" generator, not
+ "sequence"), this INSERT happens immediately, no matter if you are inside
or
+ outside of a transaction. This is problematic in a long-running conversation
+ with an extended Session/persistence context.
+ </para>
+ </listitem>
+ </itemizedlist>
<para>
Alternativamente, puedes asignar el identificador usando una
versión sobrecargada
de <literal>save()</literal>.
@@ -312,8 +333,8 @@
while ( kittensAndMothers.hasNext() ) {
Object[] tuple = (Object[]) kittensAndMothers.next();
- Cat kitten = (Cat) tuple[0];
- Cat mother = (Cat) tuple[1];
+ Cat kitten = (Cat) tuple[0];
+ Cat mother = (Cat) tuple[1];
....
}]]></programlisting>
@@ -485,7 +506,13 @@
usado; puedes además definir consultas SQL nativas en
metadatos, o migrar
consultas existentes a Hibernate colocándolas en ficheros
de mapeo.
</para>
-
+ <para> UNTRANSLATED!
+ Also note that a query declaration inside a
<literal><hibernate-mapping></literal>
+ element requires a global unique name for the query, while a query declaration inside
a
+ <literal><class></literal> element is made unique
automatically by prepending the
+ fully qualified name of the class, for example
+ <literal>eg.Cat.ByNameAndMaximumWeight</literal>.
+ </para>
</sect3>
</sect2>
@@ -567,16 +594,16 @@
Hibernate, debes encerrar los alias de SQL entre llaves:
</para>
- <programlisting><![CDATA[List cats =
session.createSQLQuery("SELECT {cat.*} FROM CAT {cat} WHERE ROWNUM<10")
- .addEntity("cat", Cat.class)
-.list();]]></programlisting>
-
- <programlisting><![CDATA[List cats = session.createSQLQuery(
- "SELECT {cat}.ID AS {cat.id}, {cat}.SEX AS {cat.sex}, " +
- "{cat}.MATE AS {cat.mate}, {cat}.SUBCLASS AS {cat.class}, ... " +
- "FROM CAT {cat} WHERE ROWNUM<10")
- .addEntity("cat", Cat.class)
-.list()]]></programlisting>
+ <programlisting><![CDATA[List cats =
session.createSQLQuery("SELECT {cat.*} FROM CAT {cat} WHERE ROWNUM<10")
+ .addEntity("cat", Cat.class)
+.list();]]></programlisting>
+
+ <programlisting><![CDATA[List cats = session.createSQLQuery(
+ "SELECT {cat}.ID AS {cat.id}, {cat}.SEX AS {cat.sex}, " +
+ "{cat}.MATE AS {cat.mate}, {cat}.SUBCLASS AS {cat.class}, ... " +
+ "FROM CAT {cat} WHERE ROWNUM<10")
+ .addEntity("cat", Cat.class)
+.list()]]></programlisting>
<para>
Las consultas SQL pueden contener parámetros con nombre y
posicionales, al igual que
@@ -1187,7 +1214,14 @@
</para>
</listitem>
</itemizedlist>
-
+ <para> UNTRANSLATED!!!
+ Finally, note that cascading of operations can be applied to an object graph at
+ <emphasis>call time</emphasis> or at <emphasis>flush
time</emphasis>. All operations,
+ if enabled, are cascaded to associated entities reachable when the operation is
+ executed. However, <literal>save-upate</literal> and
<literal>delete-orphan</literal>
+ are transitive for all associated entities reachable during flush of the
+ <literal>Session</literal>.
+ </para>
</sect1>
<sect1 id="objectstate-metadata">
Modified:
core/trunk/documentation/manual/es-ES/src/main/docbook/content/toolset_guide.xml
===================================================================
---
core/trunk/documentation/manual/es-ES/src/main/docbook/content/toolset_guide.xml 2007-10-27
03:50:07 UTC (rev 14152)
+++
core/trunk/documentation/manual/es-ES/src/main/docbook/content/toolset_guide.xml 2007-10-27
12:53:39 UTC (rev 14153)
@@ -77,46 +77,69 @@
Con este atributo puedes establecer el tamaño de una columna.
(O, para tipos de datos
numéricos/decimales, la precisión.)
</para>
-
+ <programlisting><![CDATA[<property name="zip"
length="5"/>]]></programlisting>
+ <programlisting><![CDATA[<property name="balance"
precision="12" scale="2"/>]]></programlisting>
<para>
Algunas etiquetas también aceptan un atributo
<literal>not-null</literal> (para generar una restricción
<literal>NOT NULL</literal> en columnas de tablas) y y un
atributo <literal>unique</literal> (para generar
restricciones <literal>UNIQUE</literal> en columnas de
tablas).
</para>
+ <programlisting><![CDATA[<many-to-one name="bar"
column="barId" not-null="true"/>]]></programlisting>
+
+ <programlisting><![CDATA[<element column="serialNumber"
type="long" not-null="true"
unique="true"/>]]></programlisting>
+
+ <para>
+ A <literal>unique-key</literal> attribute may be used to group columns
in
+ a single unique key constraint. Currently, the specified value of the
+ <literal>unique-key</literal> attribute is
<emphasis>not</emphasis> used
+ to name the constraint in the generated DDL, only to group the columns in
+ the mapping file.
+ </para>
+
+ <programlisting><![CDATA[<many-to-one name="org"
column="orgId" unique-key="OrgEmployeeId"/>
+<property name="employeeId"
unique-key="OrgEmployee"/>]]></programlisting>
+<para>
+ An <literal>index</literal> attribute specifies the name of an index that
+ will be created using the mapped column or columns. Multiple columns may be
+ grouped into the same index, simply by specifying the same index name.
+</para>
- <para>
- Algunas etiquetas aceptan un atributo
<literal>index</literal> para especificar el nombre de un índice
- para esa columna. Se puede usar un atributo
<literal>unique-key</literal> para agrupar columnas en una
- restricción de clave de una sola unidad. Actualmente, el valor
especificado del atributo
- <literal>unique-key</literal>
<emphasis>no</emphasis> es usado para nombrar la restricción,
sólo para
- agrupar las columnas en el fichero de mapeo.
- </para>
-
- <para>
- Ejemplos:
- </para>
+<programlisting><![CDATA[<property name="lastName"
index="CustName"/>
+ <property name="firstName"
index="CustName"/>]]></programlisting>
- <programlisting><![CDATA[<property name="foo"
type="string" length="64" not-null="true"/>
+<para>
+ A <literal>foreign-key</literal> attribute may be used to override the name
+ of any generated foreign key constraint.
+</para>
-<many-to-one name="bar" foreign-key="fk_foo_bar"
not-null="true"/>
+<programlisting><![CDATA[<many-to-one name="bar"
column="barId"
foreign-key="FKFooBar"/>]]></programlisting>
-<element column="serial_number" type="long"
not-null="true" unique="true"/>]]></programlisting>
+<para>
+ Many mapping elements also accept a child
<literal><column></literal> element.
+ This is particularly useful for mapping multi-column types:
+</para>
- <para>
- Alternativamente, estos elementos aceptan tambíen un elemento
hijo <literal><column></literal>.
- Esto es particularmente útil para tipos multicolumnas:
- </para>
-
- <programlisting><![CDATA[<property name="foo"
type="string">
- <column name="foo" length="64" not-null="true"
sql-type="text"/>
+<programlisting><![CDATA[<property name="name"
type="my.customtypes.Name"/>
+ <column name="last" not-null="true" index="bar_idx"
length="30"/>
+ <column name="first" not-null="true" index="bar_idx"
length="20"/>
+ <column name="initial"/>
</property>]]></programlisting>
- <programlisting><![CDATA[<property name="bar"
type="my.customtypes.MultiColumnType"/>
- <column name="fee" not-null="true"
index="bar_idx"/>
- <column name="fi" not-null="true"
index="bar_idx"/>
- <column name="fo" not-null="true"
index="bar_idx"/>
-</property>]]></programlisting>
+<para>
+ The <literal>default</literal> attribute lets you specify a default value
for
+ a column (you should assign the same value to the mapped property before
+ saving a new instance of the mapped class).
+</para>
+<programlisting><![CDATA[<property name="credits"
type="integer" insert="false">
+ <column name="credits" default="10"/>
+ </property>]]></programlisting>
+
+<programlisting><![CDATA[<version name="version"
type="integer" insert="false">
+ <column name="version" default="0"/>
+ </property>]]></programlisting>
+
+
<para>
El atributo <literal>sql-type</literal> permite al usuario
sobrescribir el mapeo por defecto de
tipo Hibernate a tipo de datos SQL.
@@ -155,7 +178,16 @@
<entry>number</entry>
<entry>largo de columna/precisión
decimal</entry>
</row>
- <row>
+ <row> <row>
+ <entry><literal>precision</literal></entry>
+ <entry>number</entry>
+ <entry>column decimal precision</entry>
+ </row>
+ <row>
+ <entry><literal>scale</literal></entry>
+ <entry>number</entry>
+ <entry>column decimal scale</entry>
+ </row>
<entry><literal>not-null</literal></entry>
<entry><literal>true|false</literal></entry>
<entry>especifica que la columna debe ser no
nulable</entry>
@@ -180,8 +212,9 @@
<entry><literal>foreign_key_name</literal></entry>
<entry>
especifica el nombre de la restricción de
clave foránea generada por una
- asociación, úsalo en los elementos
de mapeo <one-to-one>, <many-to-one>,
- <key>, y <many-to-many>. Nota
que los lados
+ asociación, úsalo e
<literal><one-to-one></literal>,
+ <literal><many-to-one></literal>,
<literal><key></literal>,
+ or
<literal><many-to-many></literal> . Nota que los lados
<literal>inverse="true"</literal>
no serán considerados por
<literal>SchemaExport</literal>.
</entry>
@@ -193,6 +226,12 @@
sobrescribe el tipo de columna por defecto
(sólo atributo del elemento
<literal><column></literal>)
</entry>
+ </row> <row>
+ <entry><literal>default</literal></entry>
+ <entry>SQL expression</entry>
+ <entry>
+ specify a default value for the column
+ </entry>
</row>
<row>
<entry><literal>check</literal></entry>
@@ -260,6 +299,9 @@
<row>
<entry><literal>--drop</literal></entry>
<entry>sólo desechar las
tablas</entry>
+ </row> <row>
+ <entry><literal>--create</literal></entry>
+ <entry>only create the tables</entry>
</row>
<row>
<entry><literal>--text</literal></entry>
@@ -268,6 +310,9 @@
<row>
<entry><literal>--output=my_schema.ddl</literal></entry>
<entry>enviar la salida del guión ddl a un
fichero</entry>
+ </row> <row>
+
<entry><literal>--naming=eg.MyNamingStrategy</literal></entry>
+ <entry>select a <literal>NamingStrategy</literal></entry>
</row>
<row>
<entry><literal>--config=hibernate.cfg.xml</literal></entry>
@@ -415,10 +460,20 @@
<row>
<entry><literal>--quiet</literal></entry>
<entry>no enviar a salida estándar el
guión</entry>
+ </row> <row>
+ <entry><literal>--text</literal></entry>
+ <entry>don't export the script to the database</entry>
+ </row>
+ <row>
+
<entry><literal>--naming=eg.MyNamingStrategy</literal></entry>
+ <entry>select a <literal>NamingStrategy</literal></entry>
</row>
<row>
<entry><literal>--properties=hibernate.properties</literal></entry>
<entry>lee las propiedades de base de datos de un
fichero</entry>
+ </row> <row>
+
<entry><literal>--config=hibernate.cfg.xml</literal></entry>
+ <entry>specify a <literal>.cfg.xml</literal> file</entry>
</row>
</tbody>
</tgroup>
Modified: core/trunk/documentation/manual/es-ES/src/main/docbook/content/transactions.xml
===================================================================
---
core/trunk/documentation/manual/es-ES/src/main/docbook/content/transactions.xml 2007-10-27
03:50:07 UTC (rev 14152)
+++
core/trunk/documentation/manual/es-ES/src/main/docbook/content/transactions.xml 2007-10-27
12:53:39 UTC (rev 14153)
@@ -14,8 +14,14 @@
Básicamente, usa Hibernate como usarías JDBC directo (o
JTA/CMT) con tus recursos de base de
datos.
</para>
-
<para>
+ Hibernate does not lock objects in memory. Your application can expect the behavior
as
+ defined by the isolation level of your database transactions. Note that thanks to
the
+ <literal>Session</literal>, which is also a transaction-scoped cache,
Hibernate
+ provides repeatable reads for lookup by identifier and entity queries (not
+ reporting queries that return scalar values).
+ </para>
+ <para>
Sin embargo, además del versionado automático, Hibernate
ofrece una API (menor) para
bloqueo pesimista de filas, usando la sintáxis <literal>SELECT
FOR UPDATE</literal>.
Esta API se discute más adelante en este capítulo:
@@ -90,22 +96,37 @@
aplicaciones.
</para>
- <para>
- El desafío yace en la implementación: no
sólo tienen que comenzarse y terminarse correctamente
- la <literal>Session</literal> y la transacción,
sino que además tienen que estar accesibles
- para las operaciones de acceso a datos. La demarcación de una
unidad de trabajo se implementa
- idealmente usando un interceptor que se ejecuta cuando una
petición llama al servidor y anter que
- la respuesta sea enviada (es decir, un
<literal>ServletFilter</literal>). Recomendamos ligar la
- <literal>Session</literal> a la hebra que atiende la
petición, usando una variable
- <literal>ThreadLocal</literal>. Esto permite un
fácil acceso (como acceder a una variable static)
- en tódo el código que se ejecuta en esta hebra.
Dependiendo del mecanismo de demarcación de
- transacciones de base de datos que elijas, podrías mantener
también el contexto de la transacción
- en una variable <literal>ThreadLocal</literal>. Los patrones
de implementación para esto son
- conocidos como <emphasis>Sesión Local de Hebra
(ThreadLocal Session)</emphasis> y
- <emphasis>Sesión Abierta en Vista (Open Session in
View)</emphasis>. Puedes extender fácilmente
- la clase de ayuda <literal>HibernateUtil</literal> mostrada
anteriormente para encontrar
- una forma de implementar un interceptor e instalarlo en tu entorno. Ver
el sitio web de Hibernate
- para consejos y ejemplos.
+ <para>
+ The challenge lies in the implementation. Hibernate provides built-in management
of
+ the "current session" to simplify this pattern. All you have to do is
start a
+ transaction when a server request has to be processed, and end the transaction
+ before the response is send to the client. You can do this in any way you
+ like, common solutions are <literal>ServletFilter</literal>, AOP
interceptor with a
+ pointcut on the service methods, or a proxy/interception container. An EJB
container
+ is a standardized way to implement cross-cutting aspects such as transaction
+ demarcation on EJB session beans, declaratively with CMT. If you decide to
+ use programmatic transaction demarcation, prefer the Hibernate
<literal>Transaction</literal>
+ API shown later in this chapter, for ease of use and code portability.
+ </para>
+
+ <para>
+ Your application code can access a "current session" to process the
request
+ by simply calling <literal>sessionFactory.getCurrentSession()</literal>
anywhere
+ and as often as needed. You will always get a
<literal>Session</literal> scoped
+ to the current database transaction. This has to be configured for either
+ resource-local or JTA environments, see <xref
linkend="architecture-current-session"/>.
+ </para>
+
+ <para>
+ Sometimes it is convenient to extend the scope of a
<literal>Session</literal> and
+ database transaction until the "view has been rendered". This is
especially useful
+ in servlet applications that utilize a separate rendering phase after the request
+ has been processed. Extending the database transaction until view rendering is
+ complete is easy to do if you implement your own interceptor. However, it is not
+ easily doable if you rely on EJBs with container-managed transactions, as a
+ transaction will be completed when an EJB method returns, before rendering of any
+ view can start. See the Hibernate website and forum for tips and examples around
+ this <emphasis>Open Session in View</emphasis> pattern.
</para>
</sect2>
@@ -421,9 +442,7 @@
<para>
No tienes que limpiar con <literal>flush()</literal> la
<literal>Session</literal> explícitamente -
la llamada a <literal>commit()</literal>
automáticamente dispara la sincronización.
- </para>
-
- <para>
+
Una llamada a <literal>close()</literal> marca el fin de una
sesión. La principal implicación
de <literal>close()</literal> es que la conexión
JDBC será abandonada por la sesión.
</para>
@@ -624,6 +643,50 @@
</sect2>
+
+ <sect2 id="transactions-demarcation-timeout">
+ <title>Transaction timeout</title>
+
+ <para>
+ One extremely important feature provided by a managed environment like EJB
+ that is never provided for non-managed code is transaction timeout. Transaction
+ timeouts ensure that no misbehaving transaction can indefinitely tie up
+ resources while returning no response to the user. Outside a managed (JTA)
+ environment, Hibernate cannot fully provide this functionality. However,
+ Hibernate can at least control data access operations, ensuring that database
+ level deadlocks and queries with huge result sets are limited by a defined
+ timeout. In a managed environment, Hibernate can delegate transaction timeout
+ to JTA. This functioanlity is abstracted by the Hibernate
+ <literal>Transaction</literal> object.
+ </para>
+
+ <programlisting><![CDATA[
+ Session sess = factory.openSession();
+ try {
+ //set transaction timeout to 3 seconds
+ sess.getTransaction().setTimeout(3);
+ sess.getTransaction().begin();
+
+ // do some work
+ ...
+
+ sess.getTransaction().commit()
+ }
+ catch (RuntimeException e) {
+ sess.getTransaction().rollback();
+ throw e; // or display error message
+ }
+ finally {
+ sess.close();
+ }]]></programlisting>
+
+ <para>
+ Note that <literal>setTimeout()</literal> may not be called in a CMT
bean,
+ where transaction timeouts must be defined declaratively.
+ </para>
+
+ </sect2>
+
</sect1>
@@ -700,7 +763,7 @@
La <literal>Session</literal> se desconecta de cualquier
conexión JDBC subyacente
al esperar por una interacción del usuario. Este enfoque es el
más eficiente en términos
de acceso a base de datos. La aplicación no necesita tratar
por sí misma con el chequeo de
- versiones, ni re-uniendo instancias separadas, ni tiene que recargar
instancias en cada
+ versiones, ni re-uniendo instancias separadas, ni tiene que recargar
instancias en cadatransactions-demarcation-timeout
transacción de base de datos.
</para>
@@ -742,7 +805,12 @@
<literal>Session</literal> y no transferirla a la capa web
para almacenarla en la
<literal>HttpSession</literal> (ni incluso serializarla a una
capa separada).
</para>
-
+ <para> UNTRANSLATED!!!
+ The extended session pattern, or
<emphasis>session-per-conversation</emphasis>, is
+ more difficult to implement with automatic current session context management.
+ You need to supply your own implementation of the
<literal>CurrentSessionContext</literal>
+ for this, see the Hibernate Wiki for examples.
+ </para>
</sect2>
<sect2 id="transactions-optimistic-detached">
Modified: core/trunk/documentation/manual/es-ES/src/main/docbook/content/tutorial.xml
===================================================================
--- core/trunk/documentation/manual/es-ES/src/main/docbook/content/tutorial.xml 2007-10-27
03:50:07 UTC (rev 14152)
+++ core/trunk/documentation/manual/es-ES/src/main/docbook/content/tutorial.xml 2007-10-27
12:53:39 UTC (rev 14153)
@@ -19,6 +19,10 @@
Michael Gloegl. Las bibliotecas de terceros que mencionamos son para JDK 1.4
y 5.0. Podrías necesitar otras para JDK 1.3.
</para>
+ <para> UNTRANSLATED!!!
+ The source code for the tutorial is included in the distribution in the
+ <literal>doc/reference/tutorial/</literal> directory.
+ </para>
</sect1>
@@ -785,18 +789,40 @@
a la base de datosy poblará los objetos
<literal>Event</literal> con datos.
Puedes, por supuesto, crear consultas más complejas con HQL.
</para>
-
- <para>
- Si ahora llamas a Ant con <literal>-Daction=list</literal>,
debes ver los eventos
- que has almacenado hasta ahora. Puede sorprenderte que esto no funcione,
al menos
- si has seguido este tutorial paso por paso; el resultado siempre
estará
- vacío. La razon de esto es la opción
<literal>hbm2ddl.auto</literal>
- en la configuración de Hibernate: Hibernate
recreará la base de datos
- en cada ejecución. Deshabilítala quitando la
opción, y verás
- resultados en tu listado después que llames a la
acción <literal>store</literal>
- unas cuantas veces. La generación y exportación de
esquema es útil
- mayormente en testeo unitario.
+
+ <para>
+ Now, to execute and test all of this, follow these steps:
</para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Run <literal>ant run -Daction=store</literal> to store something into
the database
+ and, of course, to generate the database schema before through hbm2ddl.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Now disable hbm2ddl by commenting out the property in your
<literal>hibernate.cfg.xml</literal>
+ file. Usually you only leave it turned on in continous unit testing, but another
+ run of hbm2ddl would <emphasis>drop</emphasis> everything you have
stored - the
+ <literal>create</literal> configuration setting actually translates
into "drop all
+ tables from the schema, then re-create all tables, when the SessionFactory is
build".
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ If you now call Ant with <literal>-Daction=list</literal>, you should
see the events
+ you have stored so far. You can of course also call the
<literal>store</literal> action a few
+ times more.
+ </para>
+
+ <para>
+ Note: Most new Hibernate users fail at this point and we see questions about
+ <emphasis>Table not found</emphasis> error messages regularly. However,
if you follow the
+ steps outlined above you will not have this problem, as hbm2ddl creates the
database
+ schema on the first run, and subsequent application restarts will use this schema.
If
+ you change the mapping and/or database schema, you have to re-enable hbm2ddl once
again.
+ </para>
</sect2>
@@ -1119,11 +1145,25 @@
direcciones de email duplicadas por persona, que es exactamente la
semántica
que necesitamos para un conjunto en Java.
</para>
-
+ <programlisting><![CDATA[private void addEmailToPerson(Long personId,
String emailAddress) {
+
+ Session session = HibernateUtil.getSessionFactory().getCurrentSession();
+ session.beginTransaction();
+
+ Person aPerson = (Person) session.load(Person.class, personId);
+
+ // The getEmailAddresses() might trigger a lazy load of the collection
+ aPerson.getEmailAddresses().add(emailAddress);
+
+ session.getTransaction().commit();
+}]]></programlisting>
<para>
Puedes ahora intentar y agregar elementos a esta colección, al
igual que
- hicimos antes enlazando personas y eventos. Es el mismo código
en Java.
- </para>
+ hicimos antes enlazando personas y eventos. Es el mismo código en
Java.</para><para>
+ This time we didnt' use a <emphasis>fetch</emphasis> query to
initialize the collection.
+ Hence, the call to its getter method will trigger an additional select to initialize
+ it, so we can add an element to it. Monitor the SQL log and try to optimize this with
+ an eager fetch.</para>
</sect2>
@@ -1246,8 +1286,280 @@
</para>
-->
</sect2>
- </sect1>
+ <para>
+ Let's turn this into a small web application.
+ </para>
+</sect1>
+<sect1 id="tutorial-webapp">
+ <title>Part 3 - The EventManager web application</title>
+
+ <para>
+ A Hibernate web application uses <literal>Session</literal> and
<literal>Transaction</literal>
+ almost like a standalone application. However, some common patterns are useful. We now
write
+ an <literal>EventManagerServlet</literal>. This servlet can list all events
stored in the
+ database, and it provides an HTML form to enter new events.
+ </para>
+
+ <sect2 id="tutorial-webapp-servlet" revision="2">
+ <title>Writing the basic servlet</title>
+
+ <para>
+ Create a new class in your source directory, in the
<literal>events</literal>
+ package:
+ </para>
+
+ <programlisting><![CDATA[package events;
+
+ // Imports
+
+ public class EventManagerServlet extends HttpServlet {
+
+ // Servlet code
+ }]]></programlisting>
+
+ <para>
+ The servlet handles HTTP <literal>GET</literal> requests only, hence, the
method
+ we implement is <literal>doGet()</literal>:
+ </para>
+
+ <programlisting><![CDATA[protected void doGet(HttpServletRequest request,
+ HttpServletResponse response)
+ throws ServletException, IOException {
+
+ SimpleDateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy");
+
+ try {
+ // Begin unit of work
+ HibernateUtil.getSessionFactory()
+ .getCurrentSession().beginTransaction();
+
+ // Process request and render page...
+
+ // End unit of work
+ HibernateUtil.getSessionFactory()
+ .getCurrentSession().getTransaction().commit();
+
+ } catch (Exception ex) {
+ HibernateUtil.getSessionFactory()
+ .getCurrentSession().getTransaction().rollback();
+ throw new ServletException(ex);
+ }
+
+ }]]></programlisting>
+
+ <para>
+ The pattern we are applying here is called
<emphasis>session-per-request</emphasis>.
+ When a request hits the servlet, a new Hibernate
<literal>Session</literal> is
+ opened through the first call to <literal>getCurrentSession()</literal> on
the
+ <literal>SessionFactory</literal>. Then a database transaction is
started—all
+ data access as to occur inside a transaction, no matter if data is read or written
+ (we don't use the auto-commit mode in applications).
+ </para>
+
+ <para>
+ Do <emphasis>not</emphasis> use a new Hibernate
<literal>Session</literal> for
+ every database operation. Use one Hibernate <literal>Session</literal>
that is
+ scoped to the whole request. Use <literal>getCurrentSession()</literal>,
so that
+ it is automatically bound to the current Java thread.
+ </para>
+
+ <para>
+ Next, the possible actions of the request are processed and the response HTML
+ is rendered. We'll get to that part soon.
+ </para>
+
+ <para>
+ Finally, the unit of work ends when processing and rendering is complete. If any
+ problem occured during processing or rendering, an exception will be thrown
+ and the database transaction rolled back. This completes the
+ <literal>session-per-request</literal> pattern. Instead of the
transaction
+ demarcation code in every servlet you could also write a servlet filter.
+ See the Hibernate website and Wiki for more information about this pattern,
+ called <emphasis>Open Session in View</emphasis>—you'll need
it as soon
+ as you consider rendering your view in JSP, not in a servlet.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-webapp-processing" revision="1">
+ <title>Processing and rendering</title>
+
+ <para>
+ Let's implement the processing of the request and rendering of the page.
+ </para>
+
+ <programlisting><![CDATA[// Write HTML header
+ PrintWriter out = response.getWriter();
+ out.println("<html><head><title>Event
Manager</title></head><body>");
+
+ // Handle actions
+ if ( "store".equals(request.getParameter("action")) ) {
+
+ String eventTitle = request.getParameter("eventTitle");
+ String eventDate = request.getParameter("eventDate");
+
+ if ( "".equals(eventTitle) || "".equals(eventDate) ) {
+ out.println("<b><i>Please enter event title and
date.</i></b>");
+ } else {
+ createAndStoreEvent(eventTitle, dateFormatter.parse(eventDate));
+ out.println("<b><i>Added event.</i></b>");
+ }
+ }
+
+ // Print page
+ printEventForm(out);
+ listEvents(out, dateFormatter);
+
+ // Write HTML footer
+ out.println("</body></html>");
+ out.flush();
+ out.close();]]></programlisting>
+
+ <para>
+ Granted, this coding style with a mix of Java and HTML would not scale
+ in a more complex application—keep in mind that we are only
illustrating
+ basic Hibernate concepts in this tutorial. The code prints an HTML
+ header and a footer. Inside this page, an HTML form for event entry and
+ a list of all events in the database are printed. The first method is
+ trivial and only outputs HTML:
+ </para>
+
+ <programlisting><![CDATA[private void printEventForm(PrintWriter out) {
+ out.println("<h2>Add new event:</h2>");
+ out.println("<form>");
+ out.println("Title: <input name='eventTitle'
length='50'/><br/>");
+ out.println("Date (e.g. 24.12.2009): <input
name='eventDate' length='10'/><br/>");
+ out.println("<input type='submit' name='action'
value='store'/>");
+ out.println("</form>");
+ }]]></programlisting>
+
+ <para>
+ The <literal>listEvents()</literal> method uses the Hibernate
+ <literal>Session</literal> bound to the current thread to
execute
+ a query:
+ </para>
+
+ <programlisting><![CDATA[private void listEvents(PrintWriter out,
SimpleDateFormat dateFormatter) {
+
+ List result = HibernateUtil.getSessionFactory()
+ .getCurrentSession().createCriteria(Event.class).list();
+ if (result.size() > 0) {
+ out.println("<h2>Events in database:</h2>");
+ out.println("<table border='1'>");
+ out.println("<tr>");
+ out.println("<th>Event title</th>");
+ out.println("<th>Event date</th>");
+ out.println("</tr>");
+ for (Iterator it = result.iterator(); it.hasNext();) {
+ Event event = (Event) it.next();
+ out.println("<tr>");
+ out.println("<td>" + event.getTitle() +
"</td>");
+ out.println("<td>" + dateFormatter.format(event.getDate()) +
"</td>");
+ out.println("</tr>");
+ }
+ out.println("</table>");
+ }
+ }]]></programlisting>
+
+ <para>
+ Finally, the <literal>store</literal> action is dispatched to the
+ <literal>createAndStoreEvent()</literal> method, which also uses
+ the <literal>Session</literal> of the current thread:
+ </para>
+
+ <programlisting><![CDATA[protected void createAndStoreEvent(String title,
Date theDate) {
+ Event theEvent = new Event();
+ theEvent.setTitle(title);
+ theEvent.setDate(theDate);
+
+ HibernateUtil.getSessionFactory()
+ .getCurrentSession().save(theEvent);
+ }]]></programlisting>
+
+ <para>
+ That's it, the servlet is complete. A request to the servlet will be
processed
+ in a single <literal>Session</literal> and
<literal>Transaction</literal>. As
+ earlier in the standalone application, Hibernate can automatically bind these
+ ojects to the current thread of execution. This gives you the freedom to layer
+ your code and access the <literal>SessionFactory</literal> in any way
you like.
+ Usually you'd use a more sophisticated design and move the data access code
+ into data access objects (the DAO pattern). See the Hibernate Wiki for more
+ examples.
+ </para>
+
+ </sect2>
+
+ <sect2 id="tutorial-webapp-deploy">
+ <title>Deploying and testing</title>
+
+ <para>
+ To deploy this application you have to create a web archive, a WAR. Add the
+ following Ant target to your <literal>build.xml</literal>:
+ </para>
+
+ <programlisting><![CDATA[<target name="war"
depends="compile">
+ <war destfile="hibernate-tutorial.war"
webxml="web.xml">
+ <lib dir="${librarydir}">
+ <exclude name="jsdk*.jar"/>
+ </lib>
+
+ <classes dir="${targetdir}"/>
+ </war>
+ </target>]]></programlisting>
+
+ <para>
+ This target creates a file called
<literal>hibernate-tutorial.war</literal>
+ in your project directory. It packages all libraries and the
<literal>web.xml</literal>
+ descriptor, which is expected in the base directory of your project:
+ </para>
+
+ <programlisting><![CDATA[<?xml version="1.0"
encoding="UTF-8"?>
+ <web-app version="2.4"
+
xmlns="http://java.sun.com/xml/ns/j2ee"
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
+
+ <servlet>
+ <servlet-name>Event Manager</servlet-name>
+ <servlet-class>events.EventManagerServlet</servlet-class>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>Event Manager</servlet-name>
+ <url-pattern>/eventmanager</url-pattern>
+ </servlet-mapping>
+ </web-app>]]></programlisting>
+
+ <para>
+ Before you compile and deploy the web application, note that an additional
library
+ is required: <literal>jsdk.jar</literal>. This is the Java servlet
development kit,
+ if you don't have this library already, get it from the Sun website and copy
it to
+ your library directory. However, it will be only used for compliation and
excluded
+ from the WAR package.
+ </para>
+
+ <para>
+ To build and deploy call <literal>ant war</literal> in your project
directory
+ and copy the <literal>hibernate-tutorial.war</literal> file into your
Tomcat
+ <literal>webapp</literal> directory. If you don't have Tomcat
installed, download
+ it and follow the installation instructions. You don't have to change any
Tomcat
+ configuration to deploy this application though.
+ </para>
+
+ <para>
+ Once deployed and Tomcat is running, access the application at
+ <literal>http://localhost:8080/hibernate-tutorial/eventmanager</literal>.
Make
+ sure you watch the Tomcat log to see Hibernate initialize when the first
+ request hits your servlet (the static initializer in
<literal>HibernateUtil</literal>
+ is called) and to get the detailed output if any exceptions occurs.
+ </para>
+
+ </sect2>
+
+ </sect1>
+
+
<sect1 id="tutorial-summary">
<title>Summary</title>