From: <fab...@us...> - 2009-07-14 01:36:04
|
Revision: 4610 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4610&view=rev Author: fabiomaulo Date: 2009-07-14 01:36:03 +0000 (Tue, 14 Jul 2009) Log Message: ----------- Merge r4609 Modified Paths: -------------- trunk/nhibernate/doc/reference/modules/example_mappings.xml Added Paths: ----------- trunk/nhibernate/doc/reference/images/AuthorWork.png trunk/nhibernate/doc/reference/images/CustomerOrderProduct.png Removed Paths: ------------- trunk/nhibernate/doc/reference/images/AuthorWork.gif trunk/nhibernate/doc/reference/images/AuthorWork.zargo trunk/nhibernate/doc/reference/images/CustomerOrderProduct.gif trunk/nhibernate/doc/reference/images/CustomerOrderProduct.zargo Deleted: trunk/nhibernate/doc/reference/images/AuthorWork.gif =================================================================== (Binary files differ) Added: trunk/nhibernate/doc/reference/images/AuthorWork.png =================================================================== (Binary files differ) Property changes on: trunk/nhibernate/doc/reference/images/AuthorWork.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Deleted: trunk/nhibernate/doc/reference/images/AuthorWork.zargo =================================================================== (Binary files differ) Deleted: trunk/nhibernate/doc/reference/images/CustomerOrderProduct.gif =================================================================== (Binary files differ) Added: trunk/nhibernate/doc/reference/images/CustomerOrderProduct.png =================================================================== (Binary files differ) Property changes on: trunk/nhibernate/doc/reference/images/CustomerOrderProduct.png ___________________________________________________________________ Added: svn:mime-type + application/octet-stream Deleted: trunk/nhibernate/doc/reference/images/CustomerOrderProduct.zargo =================================================================== (Binary files differ) Modified: trunk/nhibernate/doc/reference/modules/example_mappings.xml =================================================================== --- trunk/nhibernate/doc/reference/modules/example_mappings.xml 2009-07-14 01:34:03 UTC (rev 4609) +++ trunk/nhibernate/doc/reference/modules/example_mappings.xml 2009-07-14 01:36:03 UTC (rev 4610) @@ -136,13 +136,13 @@ <mediaobject> <imageobject role="fo"> - <imagedata fileref="images/AuthorWork.gif" format="GIF" align="center"/> + <imagedata fileref="images/AuthorWork.png" format="PNG" align="center"/> </imageobject> <imageobject role="html"> - <imagedata fileref="../shared/images/AuthorWork.gif" format="GIF" align="center"/> + <imagedata fileref="../shared/images/AuthorWork.png" format="PNG" align="center"/> </imageobject> <imageobject role="chm"> - <imagedata fileref="shared/images/AuthorWork.gif" format="GIF" align="center"/> + <imagedata fileref="shared/images/AuthorWork.png" format="PNG" align="center"/> </imageobject> </mediaobject> @@ -268,13 +268,13 @@ <mediaobject> <imageobject role="fo"> - <imagedata fileref="images/CustomerOrderProduct.gif" format="GIF" align="center"/> + <imagedata fileref="images/CustomerOrderProduct.png" format="PNG" align="center"/> </imageobject> <imageobject role="html"> - <imagedata fileref="../shared/images/CustomerOrderProduct.gif" format="GIF" align="center"/> + <imagedata fileref="../shared/images/CustomerOrderProduct.png" format="PNG" align="center"/> </imageobject> <imageobject role="chm"> - <imagedata fileref="shared/images/CustomerOrderProduct.gif" format="GIF" align="center"/> + <imagedata fileref="shared/images/CustomerOrderProduct.png" format="PNG" align="center"/> </imageobject> </mediaobject> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2009-07-14 17:32:30
|
Revision: 4618 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4618&view=rev Author: fabiomaulo Date: 2009-07-14 17:32:28 +0000 (Tue, 14 Jul 2009) Log Message: ----------- Merge r4617 Modified Paths: -------------- trunk/nhibernate/doc/reference/master.xml Added Paths: ----------- trunk/nhibernate/doc/reference/modules/batch.xml Modified: trunk/nhibernate/doc/reference/master.xml =================================================================== --- trunk/nhibernate/doc/reference/master.xml 2009-07-14 17:30:54 UTC (rev 4617) +++ trunk/nhibernate/doc/reference/master.xml 2009-07-14 17:32:28 UTC (rev 4618) @@ -13,6 +13,7 @@ <!ENTITY manipulating-data SYSTEM "modules/manipulating_data.xml"> <!ENTITY transactions SYSTEM "modules/transactions.xml"> <!ENTITY events SYSTEM "modules/events.xml"> +<!ENTITY batch SYSTEM "modules/batch.xml"> <!ENTITY query-hql SYSTEM "modules/query_hql.xml"> <!ENTITY query-criteria SYSTEM "modules/query_criteria.xml"> <!ENTITY query-sql SYSTEM "modules/query_sql.xml"> @@ -59,7 +60,7 @@ &manipulating-data; &transactions; &events; - + &batch; &query-hql; &query-criteria; &query-sql; Added: trunk/nhibernate/doc/reference/modules/batch.xml =================================================================== --- trunk/nhibernate/doc/reference/modules/batch.xml (rev 0) +++ trunk/nhibernate/doc/reference/modules/batch.xml 2009-07-14 17:32:28 UTC (rev 4618) @@ -0,0 +1,315 @@ +<chapter id="batch"> + <title>Batch processing</title> + + <para> + A naive approach to inserting 100 000 rows in the database using Hibernate might + look like this: + </para> + +<programlisting><![CDATA[ISession session = sessionFactory.OpenSession(); +ITransaction tx = session.BeginTransaction(); +for ( int i=0; i<100000; i++ ) { + Customer customer = new Customer(.....); + session.Save(customer); +} +tx.Commit(); +session.Close();]]></programlisting> + + <para> + This would fall over with an <literal>OutOfMemoryException</literal> somewhere + around the 50 000th row. That's because NHibernate caches all the newly inserted + <literal>Customer</literal> instances in the session-level cache. + </para> + + <para> + In this chapter we'll show you how to avoid this problem. First, however, if you + are doing batch processing, it is absolutely critical that you enable the use of + ADO batching, if you intend to achieve reasonable performance. Set the ADO batch + size to a reasonable number (say, 10-50): + </para> + + <programlisting><![CDATA[adonet.batch_size 20]]></programlisting> + + <para id="disablebatching" revision="1"> + Note that NHibernate disables insert batching at the ADO level transparently if you + use an <literal>identiy</literal> identifier generator. + </para> + + <para> + You also might like to do this kind of work in a process where interaction with + the second-level cache is completely disabled: + </para> + +<programlisting><![CDATA[cache.use_second_level_cache false]]></programlisting> + + <para> + 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>Batch inserts</title> + + <para> + When making new objects persistent, you must <literal>Flush()</literal> and + then <literal>Clear()</literal> the session regularly, to control the size of + the first-level cache. + </para> + +<programlisting><![CDATA[ISession session = sessionFactory.openSession(); +ITransaction tx = session.BeginTransaction(); + +for ( int i=0; i<100000; i++ ) { + Customer customer = new Customer(.....); + session.Save(customer); + if ( i % 20 == 0 ) { //20, same as the ADO batch size + //flush a batch of inserts and release memory: + session.Flush(); + session.Clear(); + } +} + +tx.Commit(); +session.Close();]]></programlisting> + + </sect1> + + <sect1 id="batch-statelesssession"> + <title>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>IStatelessSession</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 ADO. + </para> + +<programlisting><![CDATA[IStatelessSession session = sessionFactory.OpenStatelessSession(); +ITransaction tx = session.BeginTransaction(); + +var customers = session.GetNamedQuery("GetCustomers") + .Enumerable<Customer>(); +while ( customers.MoveNext() ) { + Customer customer = customers.Current; + 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>ISession</literal> + interface. + </para> + + </sect1> + + <sect1 id="batch-direct" revision="3"> + <title>DML-style operations</title> + + <para> + As already discussed, automatic and transparent object/relational mapping is concerned + with the management of object state. This implies that the object state is available + in memory, hence manipulating (using the SQL <literal>Data Manipulation Language</literal> + (DML) statements: <literal>INSERT</literal>, <literal>UPDATE</literal>, <literal>DELETE</literal>) + data directly in the database will not affect in-memory state. However, Hibernate provides methods + for bulk SQL-style DML statement execution which are performed through the + Hibernate Query Language (<link linkend="queryhql">HQL</link>). + </para> + + <para> + The pseudo-syntax for <literal>UPDATE</literal> and <literal>DELETE</literal> statements + is: <literal>( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)?</literal>. Some + points to note: + </para> + + <itemizedlist spacing="compact"> + <listitem> + <para> + In the from-clause, the FROM keyword is optional + </para> + </listitem> + <listitem> + <para> + 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 <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> + <para> + The where-clause is also optional. + </para> + </listitem> + </itemizedlist> + + <para> + As an example, to execute an HQL <literal>UPDATE</literal>, use the + <literal>IQuery.ExecuteUpdate()</literal> method: + </para> + +<programlisting><![CDATA[ISession session = sessionFactory.OpenSession(); +ITransaction 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. However, + you can force NHibernate 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[ISession session = sessionFactory.OpenSession(); +ITransaction 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>NHibernate.Usertype.IUserVersionType</literal>) + are not allowed in conjunction with a <literal>update versioned</literal> statement. + </para> + + <para> + To execute an HQL <literal>DELETE</literal>, use the same <literal>IQuery.ExecuteUpdate()</literal> + method: + </para> + +<programlisting><![CDATA[ISession session = sessionFactory.OpenSession(); +ITransaction tx = session.BeginTransaction(); + +String hqlDelete = "delete Customer c where c.name = :oldName"; +// or String hqlDelete = "delete Customer where name = :oldName"; +int deletedEntities = s.CreateQuery( hqlDelete ) + .SetString( "oldName", oldName ) + .ExecuteUpdate(); +tx.Commit(); +session.Close();]]></programlisting> + + <para> + The <literal>int</literal> value returned by the <literal>IQuery.ExecuteUpdate()</literal> + method indicate the number of entities effected by the operation. Consider this may or may not + correlate to the number of rows effected in the database. An HQL bulk operation might result in + multiple actual SQL statements being executed, for joined-subclass, for example. The returned + number indicates the number of actual entities affected by the statement. Going back to the + example of joined-subclass, a delete against one of the subclasses may actually result + in deletes against not just the table to which that subclass is mapped, but also the "root" + table and potentially joined-subclass tables further down the inheritence hierarchy. + </para> + + <para> + The pseudo-syntax for <literal>INSERT</literal> statements is: + <literal>INSERT INTO EntityName properties_list select_statement</literal>. Some + points to note: + </para> + + <itemizedlist spacing="compact"> + <listitem> + <para> + Only the INSERT INTO ... SELECT ... form is supported; not the INSERT INTO ... VALUES ... form. + </para> + <para> + The properties_list is analogous to the <literal>column speficiation</literal> + in the SQL <literal>INSERT</literal> statement. For entities involved in mapped + inheritence, only properties directly defined on that given class-level can be + used in the properties_list. Superclass properties are not allowed; and subclass + properties do not make sense. In other words, <literal>INSERT</literal> + statements are inherently non-polymorphic. + </para> + </listitem> + <listitem> + <para> + select_statement can be any valid HQL select query, with the caveat that the return types + must match the types expected by the insert. Currently, this is checked during query + compilation rather than allowing the check to relegate to the database. Note however + that this might cause problems between NHibernate <literal>Type</literal>s which are + <emphasis>equivalent</emphasis> as opposed to <emphasis>equal</emphasis>. This might cause + issues with mismatches between a property defined as a <literal>NHibernate.Type.DateType</literal> + and a property defined as a <literal>NHibernate.Type.TimestampType</literal>, even though the + database might not make a distinction or might be able to handle the conversion. + </para> + </listitem> + <listitem> + <para> + For the id property, the insert statement gives you two options. You can either + explicitly specify the id property in the properties_list (in which case its value + is taken from the corresponding select expression) or omit it from the properties_list + (in which case a generated value is used). This later option is only available when + using id generators that operate in the database; attempting to use this option with + any "in memory" type generators will cause an exception during parsing. Note that + for the purposes of this discussion, in-database generators are considered to be + <literal>NHibernate.Id.SequenceGenerator</literal> (and its subclasses) and + any implementors of <literal>NHibernate.Id.IPostInsertIdentifierGenerator</literal>. + The most notable exception here is <literal>NHibernate.Id.TableHiLoGenerator</literal>, + which cannot be used because it does not expose a selectable way to get its values. + </para> + </listitem> + <listitem> + <para> + For properties mapped as either <literal>version</literal> or <literal>timestamp</literal>, + the insert statement gives you two options. You can either specify the property in the + properties_list (in which case its value is taken from the corresponding select expressions) + or omit it from the properties_list (in which case the <literal>seed value</literal> defined + by the <literal>NHibernate.Type.IVersionType</literal> is used). + </para> + </listitem> + </itemizedlist> + + <para> + An example HQL <literal>INSERT</literal> statement execution: + </para> + +<programlisting><![CDATA[ISession session = sessionFactory.OpenSession(); +ITransaction tx = session.BeginTransaction(); + +var hqlInsert = "insert into DelinquentAccount (id, name) select c.id, c.name from Customer c where ..."; +int createdEntities = s.CreateQuery( hqlInsert ) + .ExecuteUpdate(); +tx.Commit(); +session.Close();]]></programlisting> + + </sect1> + +</chapter> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2009-07-14 17:38:36
|
Revision: 4620 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4620&view=rev Author: fabiomaulo Date: 2009-07-14 17:38:34 +0000 (Tue, 14 Jul 2009) Log Message: ----------- Merge r4619 Modified Paths: -------------- trunk/nhibernate/doc/reference/master.xml Removed Paths: ------------- trunk/nhibernate/doc/reference/modules/nhibernate_tool_hbm2net.xml trunk/nhibernate/doc/reference/modules/nullables.xml Modified: trunk/nhibernate/doc/reference/master.xml =================================================================== --- trunk/nhibernate/doc/reference/master.xml 2009-07-14 17:37:07 UTC (rev 4619) +++ trunk/nhibernate/doc/reference/master.xml 2009-07-14 17:38:34 UTC (rev 4620) @@ -82,8 +82,6 @@ &nhc-preface; &nhcaches-chapter; &nhma-chapter; - &nhbm2net-chapter; - &nullables-chapter; </part> </book> Deleted: trunk/nhibernate/doc/reference/modules/nhibernate_tool_hbm2net.xml =================================================================== --- trunk/nhibernate/doc/reference/modules/nhibernate_tool_hbm2net.xml 2009-07-14 17:37:07 UTC (rev 4619) +++ trunk/nhibernate/doc/reference/modules/nhibernate_tool_hbm2net.xml 2009-07-14 17:38:34 UTC (rev 4620) @@ -1,45 +0,0 @@ -<!-- <!DOCTYPE chapter SYSTEM "../docbook-xml/docbookx.dtd"> --> -<chapter id="tool-hbm2net"> - <title>NHibernate.Tool.hbm2net</title> - - - <abstract id="NHibernate.Tool.hbm2net-abstract"> - <title>What is NHibernate.Tool.hbm2net?</title> - <formalpara> - <title>NHibernate.Tool.hbm2net is an add-in for <ulink url="http://www.nhibernate.org">NHibernate</ulink></title> - <para>It makes it possible to generate source files from hbm.xml mapping files.</para> - </formalpara> - <para>In the directory <filename>NHibernate.Tasks</filename>, there is a tool called <command>Hbm2NetTask</command> that you can use to automate your build process (using NAnt)</para> - </abstract> - -<!-- - - <section id="NHibernate.Tool.hbm2net-howto"> - <title>How to use it?</title> - <para>!</para> - </section> - - - <section id="NHibernate.Tool.hbm2net-tips"> - <title>Tips</title> - <itemizedlist> - <listitem><para>!</para></listitem> - </itemizedlist> - </section> - - - <section id="NHibernate.Tool.hbm2net-todo"> - <title>Know issues and TODOs</title> - <para>Read TODOs in the source code ;)</para> - <para>!</para> - </section> - - - <section id="NHibernate.Tool.hbm2net-devnotes"> - <title>Developer Notes</title> - <para>!</para> - </section> - ---> - -</chapter> Deleted: trunk/nhibernate/doc/reference/modules/nullables.xml =================================================================== --- trunk/nhibernate/doc/reference/modules/nullables.xml 2009-07-14 17:37:07 UTC (rev 4619) +++ trunk/nhibernate/doc/reference/modules/nullables.xml 2009-07-14 17:38:34 UTC (rev 4620) @@ -1,110 +0,0 @@ -<!-- <!DOCTYPE chapter SYSTEM "../docbook-xml/docbookx.dtd"> --> -<chapter id="nullables"> - <title>Nullables</title> - - - <abstract id="Nullables-abstract"> - <title>What is Nullables?</title> - <formalpara> - <title>Nullables is an add-in for <ulink url="http://www.nhibernate.org">NHibernate</ulink> contributed by Donald L Mull Jr. (aka <emphasis>luggage</emphasis>)</title> - <para>Most database systems allow base types (like <classname>int</classname> or <classname>bool</classname>) to be null. This means that a boolean column can take the values <emphasis>0</emphasis>, <emphasis>1</emphasis> or <emphasis>null</emphasis>, where <emphasis>null</emphasis> doesn't have the same meaning as <emphasis>0</emphasis>. But it is not possible with .NET 1.x; a bool is always either true or false.</para> - </formalpara> - <para>Nullables makes it possible to use nullable base types in NHibernate. Note that .NET 2.0 has this feature.</para> - </abstract> - - - <section id="Nullables-howto"> - <title>How to use it?</title> - <para>Here is a simple example that uses a <classname>Nullables.NullableDateTime</classname> to (optionally) store the date of birth for a <classname>Person</classname>.</para> - <programlisting> -public <emphasis role="strong">class Person</emphasis> -{ - int _id; - string _name; - <emphasis role="strong">Nullables.NullableDateTime</emphasis> _dateOfBirth; - - public Person() - { - } - - public int Id - { - get { return this._id; } - } - - public string Name - { - get { return this._name; } - set { this._name = value; } - } - - public <emphasis role="strong">Nullables.NullableDateTime</emphasis> DateOfBirth - { - get { return this._dateOfBirth; } - set { this._dateOfBirth = value; } - } -}</programlisting> - <para>As you can see, <emphasis>DateOfBirth</emphasis> has the type <classname>Nullables.NullableDateTime</classname> (instead of <classname>System.DateTime</classname>).</para> - - <para>Here is the mapping</para> - <programlisting><![CDATA[ -<?xml version="1.0" encoding="utf-8" ?> -<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"> - <class name="Example.Person, Example" table="Person"> - <id name="Id" access="field.camelcase-underscore" unsaved-value="0"> - <generator class="native" /> - </id> - <property name="Name" type="String" length="200" /> - <]]>property name="<emphasis>DateOfBirth</emphasis>" type="<emphasis role="strong">Nullables.NHibernate.NullableDateTimeType</emphasis>, Nullables.NHibernate"<![CDATA[ /> - </class> -</hibernate-mapping>]]></programlisting> - <important> - <para>In the mapping, the type of <emphasis>DateOfBirth</emphasis> - <emphasis role="strong">must</emphasis> be <classname>Nullables.NHibernate.NullableDateTimeType</classname>. Note that <link linkend="mapping-attributes">NHibernate.Mapping.Attributes</link> handles that automatically.</para> - <para><classname>Nullables.NHibernate.NullableXXXType</classname>s are wrapper types used to translate Nullables types to Database types.</para> - </important> - - <para>Here is a piece of code using this example:</para> - <programlisting> -Person per = new Person(); - -textBox1.Text = per.DateOfBirth.Value.ToString() // will throw an exception when there is no value. - -textBox1.Text = per.DateOfBirth.ToString() // will work. it will return an empty string if there is no value. - -textBox1.Text = (per.DateOfBirth.HasValue ? per.DateOfBirth.Value.ToShortDateString() : "Unknown") // friendly message - -per.DateOfBirth = new System.DateTime(1979, 11, 8); // implicit cast from the "plain" System.DateTime. -per.DateOfBirth = new NullableDateTime(new System.DateTime(1979, 11, 8)); // the long way. - -per.DateOfBirth = null; // this works. -per.DateOfBirth = NullableDateTime.Default; // this is more correct.</programlisting> - </section> - - - <!-- - - <section id="Nullables-tips"> - <title>Tips</title> - <itemizedlist> - <listitem><para>!</para></listitem> - </itemizedlist> - </section> - - - <section id="Nullables-todo"> - <title>Know issues and TODOs</title> - <para>Read TODOs in the source code ;)</para> - <para>!</para> - </section> - - - <section id="Nullables-devnotes"> - <title>Developer Notes</title> - <para>!</para> - </section> - ---> - - -</chapter> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <ric...@us...> - 2010-11-02 07:02:24
|
Revision: 5256 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5256&view=rev Author: ricbrown Date: 2010-11-02 07:02:17 +0000 (Tue, 02 Nov 2010) Log Message: ----------- Added first-cut of QueryOver documentation. Modified Paths: -------------- trunk/nhibernate/doc/reference/master.xml Added Paths: ----------- trunk/nhibernate/doc/reference/modules/query_queryover.xml Modified: trunk/nhibernate/doc/reference/master.xml =================================================================== --- trunk/nhibernate/doc/reference/master.xml 2010-10-31 19:13:38 UTC (rev 5255) +++ trunk/nhibernate/doc/reference/master.xml 2010-11-02 07:02:17 UTC (rev 5256) @@ -16,6 +16,7 @@ <!ENTITY batch SYSTEM "modules/batch.xml"> <!ENTITY query-hql SYSTEM "modules/query_hql.xml"> <!ENTITY query-criteria SYSTEM "modules/query_criteria.xml"> +<!ENTITY query-queryover SYSTEM "modules/query_queryover.xml"> <!ENTITY query-sql SYSTEM "modules/query_sql.xml"> <!ENTITY filters SYSTEM "modules/filters.xml"> <!ENTITY performance SYSTEM "modules/performance.xml"> @@ -63,6 +64,7 @@ &batch; &query-hql; &query-criteria; + &query-queryover; &query-sql; &filters; Added: trunk/nhibernate/doc/reference/modules/query_queryover.xml =================================================================== --- trunk/nhibernate/doc/reference/modules/query_queryover.xml (rev 0) +++ trunk/nhibernate/doc/reference/modules/query_queryover.xml 2010-11-02 07:02:17 UTC (rev 5256) @@ -0,0 +1,361 @@ +<chapter id="queryqueryover"> + <title>QueryOver Queries</title> + + <para> + The ICriteria API + is NHibernate's implementation of Query Object. + NHibernate 3.0 introduces the QueryOver api, which combines the use of + Extension Methods + and + Lambda Expressions + (both new in .Net 3.5) to provide a statically typesafe wrapper round the ICriteria API. + </para> + <para> + QueryOver uses Lambda Expressions to provide some extra + syntax to remove the 'magic strings' from your ICriteria queries. + </para> + <para> + So, for example: + </para> + <programlisting><![CDATA[.Add(Expression.Eq("Name", "Smith"))]]></programlisting> + <para>becomes:</para> + <programlisting><![CDATA[.Where<Person>(p => p.Name == "Smith")]]></programlisting> + <para> + With this kind of syntax there are no 'magic strings', and refactoring tools like + 'Find All References', and 'Refactor->Rename' work perfectly. + </para> + <para> + Note: QueryOver is intended to remove the references to 'magic strings' + from the ICriteria API while maintaining it's opaqueness. It is <emphasis role="underline">not</emphasis> a LINQ provider; + NHibernate has a built-in Linq provider for this. + </para> + + <sect1 id="queryqueryover-querystructure"> + <title>Structure of a Query</title> + + <para> + Queries are created from an ISession using the syntax: + </para> + <programlisting><![CDATA[IList<Cat> cats = + session.QueryOver<Cat>() + .Where(c => c.Name == "Max") + .List();]]></programlisting> + <para> </para> + <para> + Detached QueryOver (analagous to DetachedCriteria) can be created, and then used with an ISession using: + </para> + <programlisting><![CDATA[QueryOver<Cat> query = + QueryOver.Of<Cat>() + .Where(c => c.Name == "Paddy"); + +IList<Cat> cats = + query.GetExecutableQueryOver(session) + .List();]]></programlisting> + + <para> + Queries can be built up to use restrictions, projections, and ordering using + a fluent inline syntax: + </para> + <programlisting><![CDATA[var catNames = + session.QueryOver<Cat>() + .WhereRestrictionOn(c => c.Age).IsBetween(2).And(8) + .Select(c => c.Name) + .OrderBy(c => c.Name).Asc + .List<string>();]]></programlisting> + + </sect1> + + <sect1 id="queryqueryover-simpleexpressions"> + <title>Simple Expressions</title> + + <para> + The Restrictions class (used by ICriteria) has been extended to include overloads + that allow Lambda Expression syntax. The Where() method works for simple expressions (<, <=, ==, !=, >, >=) + so instead of: + </para> + <programlisting><![CDATA[ICriterion equalCriterion = Restrictions.Eq("Name", "Max")]]></programlisting> + <para> + You can write: + </para> + <programlisting><![CDATA[ICriterion equalCriterion = Restrictions.Where<Cat>(c => c.Name == "Max")]]></programlisting> + <para> </para> + <para> + Since the QueryOver class (and IQueryOver interface) is generic and knows the type of the query, + there is an inline syntax for restrictions that does not require the additional qualification + of class name. So you can also write: + </para> + <programlisting><![CDATA[var cats = + session.QueryOver<Cat>() + .Where(c => c.Name == "Max") + .And(c => c.Age > 4) + .List();]]></programlisting> + <para> + Note, the methods Where() and And() are semantically identical; the And() method is purely to allow + QueryOver to look similar to HQL/SQL. + </para> + <para> </para> + <para> + Boolean comparisons can be made directly instead of comparing to true/false: + </para> + <programlisting><![CDATA[ .Where(p => p.IsParent) + .And(p => !p.IsRetired)]]></programlisting> + <para> </para> + <para> + Simple expressions can also be combined using the || and && operators. So ICriteria like: + </para> + <programlisting><![CDATA[ .Add(Restrictions.And( + Restrictions.Eq("Name", "test name"), + Restrictions.Or( + Restrictions.Gt("Age", 21), + Restrictions.Eq("HasCar", true))))]]></programlisting> + <para> + Can be written in QueryOver as: + </para> + <programlisting><![CDATA[ .Where(p => p.Name == "test name" && (p.Age > 21 || p.HasCar))]]></programlisting> + <para> </para> + <para> + Each of the corresponding overloads in the QueryOver API allows the use of regular ICriterion + to allow access to private properties. + </para> + <programlisting><![CDATA[ .Where(Restrictions.Eq("Name", "Max"))]]></programlisting> + <para> </para> + <para> + It is worth noting that the QueryOver API is built on top of the ICriteria API. Internally the structures are the same, so at runtime + the statement below, and the statement above, are stored as exactly the same ICriterion. The actual Lambda Expression is not stored + in the query. + </para> + <programlisting><![CDATA[ .Where(c => c.Name == "Max")]]></programlisting> + + </sect1> + + <sect1 id="queryqueryover-additionalrestrictions"> + <title>Additional Restrictions</title> + + <para> + Some SQL operators/functions do not have a direct equivalent in C#. + (e.g., the SQL <literal>where name like '%anna%'</literal>). + These operators have overloads for QueryOver in the Restrictions class, so you can write: + </para> + <programlisting><![CDATA[ .Where(Restrictions.On<Cat>(c => c.Name).IsLike("%anna%"))]]></programlisting> + <para> + There is also an inline syntax to avoid the qualification of the type: + </para> + <programlisting><![CDATA[ .WhereRestrictionOn(c => c.Name).IsLike("%anna%")]]></programlisting> + <para> </para> + <para> + While simple expressions (see above) can be combined using the || and && operators, this is not possible with the other + restrictions. So this ICriteria: + </para> + <programlisting><![CDATA[ .Add(Restrictions.Or( + Restrictions.Gt("Age", 5) + Restrictions.In("Name", new string[] { "Max", "Paddy" })))]]></programlisting> + <para> + Would have to be written as: + </para> + <programlisting><![CDATA[ .Add(Restrictions.Or( + Restrictions.Where<Cat>(c => c.Age > 5) + Restrictions.On<Cat>(c => c.Name).IsIn(new string[] { "Max", "Paddy" })))]]></programlisting> + + </sect1> + + <sect1 id="queryqueryover-associations"> + <title>Associations</title> + + <para> + QueryOver can navigate association paths using JoinQueryOver() (analagous to ICriteria.CreateCriteria() to create sub-criteria). + </para> + <para> + The factory method QuerOver<T>() on ISession returns an IQueryOver<T>. + More accurately, it returns an IQueryOver<T,T> (which inherits from IQueryOver<T>). + </para> + <para> + An IQueryOver has two types of interest; the root type (the type of entity that the query returns), + and the type of the 'current' entity being queried. For example, the following query uses + a join to create a sub-QueryOver (analagous to creating sub-criteria in the ICriteria API): + </para> + <programlisting><![CDATA[IQueryOver<Cat,Kitten> catQuery = + session.QueryOver<Cat>() + .JoinQueryOver(c => c.Kittens) + .Where(k => k.Name == "Tiddles");]]></programlisting> + <para> + The JoinQueryOver returns a new instance of the IQueryOver than has its root at the Kittens collection. + The default type for restrictions is now Kitten (restricting on the name 'Tiddles' in the above example), + while calling .List() will return an IList<Cat>. The type IQueryOver<Cat,Kitten> inherits from IQueryOver<Cat>. + </para> + <para> + Note, the overload for JoinQueryOver takes an IEnumerable<T>, and the C# compiler infers the type from that. + If your collection type is not IEnumerable<T>, then you need to qualify the type of the sub-criteria: + </para> + <programlisting>IQueryOver<Cat,Kitten> catQuery = + session.QueryOver<Cat>() + .JoinQueryOver<<emphasis>Kitten</emphasis>>(c => c.Kittens) + .Where(k => k.Name == "Tiddles");</programlisting> + <para> </para> + <para> + The default join is an inner-join. Each of the additional join types can be specified using + the methods <code>.Inner, .Left, .Right,</code> or <code>.Full</code>. + For example, to left outer-join on Kittens use: + </para> + <programlisting><![CDATA[IQueryOver<Cat,Kitten> catQuery = + session.QueryOver<Cat>() + .Left.JoinQueryOver(c => c.Kittens) + .Where(k => k.Name == "Tiddles");]]></programlisting> + + </sect1> + + <sect1 id="queryqueryover-aliases"> + <title>Aliases</title> + + <para> + In the traditional ICriteria interface aliases are assigned using 'magic strings', however their value + does not correspond to a name in the object domain. For example, when an alias is assigned using + <code>.CreateAlias("Kitten", "kittenAlias")</code>, the string "kittenAlias" does not correspond + to a property or class in the domain. + </para> + <para> + In QueryOver, aliases are assigned using an empty variable. + The variable can be declared anywhere (but should + be <code>null</code> at runtime). The compiler can then check the syntax against the variable is + used correctly, but at runtime the variable is not evaluated (it's just used as a placeholder for + the alias). + </para> + <para> + Each Lambda Expression function in QueryOver has a corresponding overload to allow use of aliases, + and a .JoinAlias function to traverse associations using aliases without creating a sub-QueryOver. + </para> + <programlisting><![CDATA[Cat catAlias = null; +Kitten kittenAlias = null; + +IQueryOver<Cat,Cat> catQuery = + session.QueryOver<Cat>(() => catAlias) + .JoinAlias(() => catAlias.Kittens, () => kittenAlias) + .Where(() => catAlias.Age > 5) + .And(() => kittenAlias.Name == "Tiddles");]]></programlisting> + + </sect1> + + <sect1 id="queryqueryover-projections"> + <title>Projections</title> + + <para> + Simple projections of the properties of the root type can be added using the <code>.Select</code> method + which can take multiple Lambda Expression arguments: + </para> + <programlisting><![CDATA[IList selection = + session.QueryOver<Cat>() + .Select( + c => c.Name, + c => c.Age) + .List<object[]>();]]></programlisting> + <para> + Because this query no longer returns a Cat, the return type must be explicitly specified. + If a single property is projected, the return type can be specified using: + </para> + <programlisting><![CDATA[IList<int> ages = + session.QueryOver<Cat>() + .Select(c => c.Age) + .List<int>();]]></programlisting> + <para> + However, if multiple properties are projected, then the returned list will contain + object arrays, as per a projection + in ICriteria. This could be fed into an anonymous type using: + </para> + <programlisting><![CDATA[var catDetails = + session.QueryOver<Cat>() + .Select( + c => c.Name, + c => c.Age) + .List<object[]>() + .Select(properties => new { + CatName = (string)properties[0], + CatAge = (int)properties[1], + }); + +Console.WriteLine(catDetails[0].CatName); +Console.WriteLine(catDetails[0].CatAge);]]></programlisting> + <para> + Note that the second <code>.Select</code> call in this example is an extension method on IEnumerable<T> supplied in System.Linq; + it is not part of NHibernate. + </para> + <para> </para> + <para> + QueryOver allows arbitrary IProjection to be added (allowing private properties to be projected). The Projections factory + class also has overloads to allow Lambda Expressions to be used: + </para> + <programlisting><![CDATA[IList selection = + session.QueryOver<Cat>() + .Select(Projections.ProjectionList() + .Add(Projections.Property<Cat>(c => c.Name)) + .Add(Projections.Avg<Cat>(c => c.Age))) + .List<object[]>();]]></programlisting> + <para> </para> + <para> + In addition there is an inline syntax for creating projection lists that does not require the explicit class qualification: + </para> + <programlisting><![CDATA[IList selection = + session.QueryOver<Cat>() + .SelectList(list => list + .Select(c => c.Name) + .SelectAvg(c => c.Age)) + .List<object[]>();]]></programlisting> + <para> </para> + <para> + Projections can also have arbitrary aliases assigned to them to allow result transformation. + If there is a CatSummary DTO class defined as: + </para> + <programlisting><![CDATA[public class CatSummary +{ + public string Name { get; set; } + public int AverageAge { get; set; } +}]]></programlisting> + <para> + ... then aliased projections can be used with the AliasToBean<T> transformer: + </para> + <programlisting><![CDATA[CatSummary summaryDto = null; +IList<CatSummary> catReport = + session.QueryOver<Cat>() + .SelectList(list => list + .SelectGroup(c => c.Name).WithAlias(() => summaryDto.Name) + .SelectAvg(c => c.Age).WithAlias(() => summaryDto.AverageAge)) + .TransformUsing(Transformers.AliasToBean<CatSummary>()) + .List<CatSummary>();]]></programlisting> + + </sect1> + + <sect1 id="queryqueryover-subqueries"> + <title>Subqueries</title> + + <para> + The Subqueries factory class has overloads to allow Lambda Expressions to express sub-query + restrictions. For example: + </para> + <programlisting><![CDATA[QueryOver<Cat> maximumAge = + QueryOver.Of<Cat>() + .SelectList(p => p.SelectMax(c => c.Age)); + +IList<Cat> oldestCats = + session.QueryOver<Cat>() + .Where(Subqueries.WhereProperty<Cat>(c => c.Age).Eq(maximumAge)) + .List();]]></programlisting> + <para> </para> + <para> + The inline syntax allows you to use subqueries without requalifying the type: + </para> + <programlisting><![CDATA[IList<Cat> oldestCats = + session.QueryOver<Cat>() + .WithSubquery.WhereProperty(c => c.Age).Eq(maximumAge) + .List();]]></programlisting> + <para> </para> + <para> + There is an extension method <code>As()</code> on (a detached) QueryOver that allows you to cast it to any type. + This is used in conjunction with the overloads <code>Where(), WhereAll(),</code> and <code>WhereSome()</code> + to allow use of the built-in C# operators for comparison, so the above query can be written as: + </para> + <programlisting><![CDATA[IList<Cat> oldestCats = + session.QueryOver<Cat>() + .WithSubquery.Where(c => c.Age == maximumAge.As<int>()) + .List();]]></programlisting> + + </sect1> + +</chapter> \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <fab...@us...> - 2010-11-25 16:35:58
|
Revision: 5270 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=5270&view=rev Author: fabiomaulo Date: 2010-11-25 16:35:51 +0000 (Thu, 25 Nov 2010) Log Message: ----------- Removed obsolete doc Modified Paths: -------------- trunk/nhibernate/doc/reference/master.xml trunk/nhibernate/doc/reference/modules/basic_mapping.xml trunk/nhibernate/doc/reference/modules/query_hql.xml trunk/nhibernate/doc/reference/modules/toolset_guide.xml Modified: trunk/nhibernate/doc/reference/master.xml =================================================================== --- trunk/nhibernate/doc/reference/master.xml 2010-11-25 03:34:05 UTC (rev 5269) +++ trunk/nhibernate/doc/reference/master.xml 2010-11-25 16:35:51 UTC (rev 5270) @@ -38,7 +38,7 @@ <bookinfo> <title>NHibernate - Relational Persistence for Idiomatic .NET</title> <subtitle>NHibernate Reference Documentation</subtitle> - <releaseinfo>2.1.0</releaseinfo> + <releaseinfo>3.0.0</releaseinfo> </bookinfo> <toc /> Modified: trunk/nhibernate/doc/reference/modules/basic_mapping.xml =================================================================== --- trunk/nhibernate/doc/reference/modules/basic_mapping.xml 2010-11-25 03:34:05 UTC (rev 5269) +++ trunk/nhibernate/doc/reference/modules/basic_mapping.xml 2010-11-25 16:35:51 UTC (rev 5270) @@ -2201,7 +2201,7 @@ <para> An <emphasis>entity</emphasis> exists independently of any other objects holding - references to the entity. Contrast this with the usual Java model where an + references to the entity. Contrast this with the usual .NET model where an unreferenced object is garbage collected. Entities must be explicitly saved and deleted (except that saves and deletions may be <emphasis>cascaded</emphasis> from a parent entity to its children). This is different from the ODMG model of Modified: trunk/nhibernate/doc/reference/modules/query_hql.xml =================================================================== --- trunk/nhibernate/doc/reference/modules/query_hql.xml 2010-11-25 03:34:05 UTC (rev 5269) +++ trunk/nhibernate/doc/reference/modules/query_hql.xml 2010-11-25 16:35:51 UTC (rev 5270) @@ -23,7 +23,7 @@ <para> This manual uses lowercase HQL keywords. Some users find queries with uppercase keywords - more readable, but we find this convention ugly when embedded in Java code. + more readable, but we find this convention ugly when embedded in C# code. </para> </sect1> @@ -381,7 +381,7 @@ <para> Likewise, the special property <literal>class</literal> accesses the discriminator value - of an instance in the case of polymorphic persistence. A Java class name embedded in the + of an instance in the case of polymorphic persistence. A .Net class name embedded in the where clause will be translated to its discriminator value. </para> Modified: trunk/nhibernate/doc/reference/modules/toolset_guide.xml =================================================================== --- trunk/nhibernate/doc/reference/modules/toolset_guide.xml 2010-11-25 03:34:05 UTC (rev 5269) +++ trunk/nhibernate/doc/reference/modules/toolset_guide.xml 2010-11-25 16:35:51 UTC (rev 5270) @@ -215,64 +215,11 @@ </para> <para> - <literal>java -cp </literal><emphasis>hibernate_classpaths</emphasis> - <literal>net.sf.hibernate.tool.hbm2ddl.SchemaExport</literal> <emphasis>options mapping_files</emphasis> + You may embed <literal>SchemaExport</literal> in your application: </para> - <table frame="topbot"> - <title><literal>SchemaExport</literal> Command Line Options</title> - <tgroup cols="2"> - <colspec colwidth="1.5*"/> - <colspec colwidth="2*"/> - <thead> - <row> - <entry>Option</entry> - <entry>Description</entry> - </row> - </thead> - <tbody> - <row> - <entry><literal>--quiet</literal></entry> - <entry>don't output the script to stdout</entry> - </row> - <row> - <entry><literal>--drop</literal></entry> - <entry>only drop the tables</entry> - </row> - <row> - <entry><literal>--text</literal></entry> - <entry>don't export to the database</entry> - </row> - <row> - <entry><literal>--output=my_schema.ddl</literal></entry> - <entry>output the ddl script to a file</entry> - </row> - <row> - <entry><literal>--config=hibernate.cfg.xml</literal></entry> - <entry>read Hibernate configuration from an XML file</entry> - </row> - <row> - <entry><literal>--properties=hibernate.properties</literal></entry> - <entry>read database properties from a file</entry> - </row> - <row> - <entry><literal>--format</literal></entry> - <entry>format the generated SQL nicely in the script</entry> - </row> - <row> - <entry><literal>--delimiter=x</literal></entry> - <entry>set an end of line delimiter for the script</entry> - </row> - </tbody> - </tgroup> - </table> - - <para> - You may even embed <literal>SchemaExport</literal> in your application: - </para> - <programlisting><![CDATA[Configuration cfg = ....; -new SchemaExport(cfg).create(false, true);]]></programlisting> +new SchemaExport(cfg).Create(false, true);]]></programlisting> </sect2> @@ -377,20 +324,19 @@ <title>Code Generation</title> <para> - The Hibernate code generator may be used to generate skeletal Java implementation classes - from a Hibernate mapping file. This tool is included in the Hibernate Extensions package - (a seperate download). + The NHibernate code generator may be used to generate skeletal C# implementation classes + from a NHibernate mapping file. This tool is included in the NHibernate Contrib package + (a seperate download in http://sourceforge.net/projects/nhcontrib/). </para> <para> - <literal>hbm2java</literal> parses the mapping files and generates fully working Java - source files from these. Thus with <literal>hbm2java</literal> one could "just" provide the - <literal>.hbm</literal> files, and then don't worry about hand-writing/coding the Java files. + <literal>hbm2net</literal> parses the mapping files and generates fully working C# + source files from these. Thus with <literal>hbm2net</literal> one could "just" provide the + <literal>.hbm</literal> files, and then don't worry about hand-writing/coding the C# files. </para> <para> - <literal>java -cp</literal> <emphasis>hibernate_classpaths</emphasis> - <literal>net.sf.hibernate.tool.hbm2java.CodeGenerator</literal> <emphasis> options + <literal>hbm2net</literal> <emphasis> options mapping_files</emphasis> </para> @@ -407,616 +353,22 @@ </thead> <tbody> <row> - <entry><literal>--output=</literal><emphasis>output_dir</emphasis></entry> + <entry><literal>-output:</literal><emphasis>output_dir</emphasis></entry> <entry>root directory for generated code</entry> </row> <row> - <entry><literal>--config=</literal><emphasis>config_file</emphasis></entry> - <entry>optional file for configuring hbm2java</entry> + <entry><literal>-config:</literal><emphasis>config_file</emphasis></entry> + <entry>optional file for configuring hbm2net</entry> </row> </tbody> </tgroup> </table> - - <sect2 id="toolsetguide-s2-1" revision="4"> - <title>The config file (optional)</title> - - <para> - The config file provides for a way to specify multiple "renderers" for the source code - and to declare <literal><meta></literal> attributes that is "global" in scope. See - more about this in the <literal><meta></literal> attribute section. - </para> - - <programlisting><![CDATA[<codegen> - <meta attribute="implements">codegen.test.IAuditable</meta> - <generate renderer="net.sf.hibernate.tool.hbm2java.BasicRenderer"/> - <generate - package="autofinders.only" - suffix="Finder" - renderer="net.sf.hibernate.tool.hbm2java.FinderRenderer"/> -</codegen>]]></programlisting> - - <para> - This config file declares a global meta attribute "implements" and specify two renderers, the - default one (BasicRenderer) and a renderer that generates Finder's (See more in "Basic Finder - generation" below). - </para> - - <para> - The second renderer is provided with a package and suffix attribute. - </para> - - <para> - The package attribute specifies that the generated source files from this renderer should be - placed here instead of the package scope specified in the <literal>.hbm</literal> files. - </para> - - <para> - The suffix attribute specifies the suffix for generated files. E.g. here a file named - <literal>Foo.java</literal> would be <literal>FooFinder.java</literal> instead. - </para> - - <para> - It is also possible to send down arbitrary parameters to the renders by adding <literal><param></literal> attributes - to the <literal><generate></literal> elements. - </para> - - <para> - hbm2java currently has support for one such parameter, - namely - <literal>generate-concrete-empty-classes</literal> which - informs the BasicRenderer to only generate empty - concrete classes that extends a base class for all your - classes. The following config.xml example illustrate - this feature - </para> - - <programlisting><![CDATA[ - <codegen> - <generate prefix="Base" renderer="net.sf.hibernate.tool.hbm2java.BasicRenderer"/> - <generate renderer="net.sf.hibernate.tool.hbm2java.BasicRenderer"> - <param name="generate-concrete-empty-classes">true</param> - <param name="baseclass-prefix">Base</param> - </generate> - </codegen>]]></programlisting> - - <para> - Notice that this config.xml configure 2 (two) - renderers. One that generates the Base classes, and a - second one that just generates empty concrete classes. - </para> - </sect2> - - <sect2 id="toolsetguide-s2-2"> - <title>The <literal>meta</literal> attribute</title> - - <para> - The <literal><meta></literal> tag is a simple way of annotating the <literal>hbm.xml</literal> - with information, so tools have a natural place to store/read information that is not directly related - to the Hibernate core. - </para> - - <para> - You can use the <literal><meta></literal> tag to tell <literal>hbm2java</literal> to only - generate "protected" setters, have classes always implement a certain set of interfaces or - even have them extend a certain base class and even more. - </para> - - <para> - The following example: - </para> - - <programlisting><![CDATA[<class name="Person"> - <meta attribute="class-description"> - Javadoc for the Person class - @author Frodo - </meta> - <meta attribute="implements">IAuditable</meta> - <id name="id" type="long"> - <meta attribute="scope-set">protected</meta> - <generator class="increment"/> - </id> - <property name="name" type="string"> - <meta attribute="field-description">The name of the person</meta> - </property> -</class>]]></programlisting> - - <para> - will produce something like the following (code shortened for better understanding). Notice the - Javadoc comment and the protected set methods: - </para> - - <programlisting><![CDATA[// default package - -import java.io.Serializable; -import org.apache.commons.lang.builder.EqualsBuilder; -import org.apache.commons.lang.builder.HashCodeBuilder; -import org.apache.commons.lang.builder.ToStringBuilder; - -/** - * Javadoc for the Person class - * @author Frodo - * - */ -public class Person implements Serializable, IAuditable { - - /** identifier field */ - public Long id; - - /** nullable persistent field */ - public String name; - - /** full constructor */ - public Person(java.lang.String name) { - this.name = name; - } - - /** default constructor */ - public Person() { - } - - public java.lang.Long getId() { - return this.id; - } - - protected void setId(java.lang.Long id) { - this.id = id; - } - - /** - * The name of the person - */ - public java.lang.String getName() { - return this.name; - } - - public void setName(java.lang.String name) { - this.name = name; - } - -}]]></programlisting> - - <table frame="topbot"> - <title>Supported meta tags</title> - <tgroup cols="2"> - <colspec colwidth="1.5*"/> - <colspec colwidth="2*"/> - <thead> - <row> - <entry>Attribute</entry> - <entry>Description</entry> - </row> - </thead> - <tbody> - <row> - <entry><literal>class-description</literal></entry> - <entry>inserted into the javadoc for classes</entry> - </row> - <row> - <entry><literal>field-description</literal></entry> - <entry>inserted into the javadoc for fields/properties</entry> - </row> - <row> - <entry><literal>interface</literal></entry> - <entry>If true an interface is generated instead of an class.</entry> - </row> - <row> - <entry><literal>implements</literal></entry> - <entry>interface the class should implement</entry> - </row> - <row> - <entry><literal>extends</literal></entry> - <entry>class the class should extend (ignored for subclasses)</entry> - </row> - <row> - <entry><literal>generated-class</literal></entry> - <entry>overrule the name of the actual class generated</entry> - </row> - <row> - <entry><literal>scope-class</literal></entry> - <entry>scope for class </entry> - </row> - <row> - <entry><literal>scope-set</literal></entry> - <entry>scope for setter method</entry> - </row> - <row> - <entry><literal>scope-get</literal></entry> - <entry>scope for getter method</entry> - </row> - <row> - <entry><literal>scope-field</literal></entry> - <entry>scope for actual field</entry> - </row> - <row> - <entry><literal>use-in-tostring</literal></entry> - <entry>include this property in the <literal>toString()</literal></entry> - </row> - <row> - <entry><literal>implement-equals</literal></entry> - <entry>include a <literal>equals()</literal> and <literal>hashCode()</literal> method in this class.</entry> - </row> - <row> - <entry><literal>use-in-equals</literal></entry> - <entry>include this property in the <literal>equals()</literal> and <literal>hashCode()</literal> method.</entry> - </row> - <row> - <entry><literal>bound</literal></entry> - <entry>add propertyChangeListener support for a property</entry> - </row> - <row> - <entry><literal>constrained</literal></entry> - <entry>bound + vetoChangeListener support for a property</entry> - </row> - <row> - <entry><literal>gen-property</literal></entry> - <entry>property will not be generated if false (use with care)</entry> - </row> - <row> - <entry><literal>property-type</literal></entry> - <entry>Overrides the default type of property. Use this with any tag's to specify the concrete type instead of just Object.</entry> - </row> - <row> - <entry><literal>class-code</literal></entry> - <entry>Extra code that will inserted at the end of the class</entry> - </row> - <row> - <entry><literal>extra-import</literal></entry> - <entry>Extra import that will inserted at the end of all other imports</entry> - </row> - <row> - <entry><literal>finder-method</literal></entry> - <entry>see "Basic finder generator" below</entry> - </row> - <row> - <entry><literal>session-method</literal></entry> - <entry>see "Basic finder generator" below</entry> - </row> - </tbody> - </tgroup> - </table> - - <para> - Attributes declared via the <literal><meta></literal> tag are per default - "inherited" inside an <literal>hbm.xml</literal> file. - </para> - - <para> - What does that mean? It means that if you e.g want to have all your classes - implement <literal>IAuditable</literal> then you just add an - <literal><meta attribute="implements">IAuditable</meta></literal> in the top of - the <literal>hbm.xml</literal> file, just after - <literal><hibernate-mapping></literal>. Now all classes defined in that - <literal>hbm.xml</literal> file will implement <literal>IAuditable</literal>! - (Except if a class also has an "implements" meta attribute, because local specified - meta tags always overrules/replaces any inherited meta tags). - </para> - - <para> - Note: This applies to <emphasis>all</emphasis> <literal><meta></literal>-tags. - Thus it can also e.g. be used to specify that all fields should be declare protected, - instead of the default private. This is done by adding <literal><meta - attribute="scope-field">protected</meta></literal> at e.g. just under the - <literal><class></literal> tag and all fields of that class will be protected. - </para> - - <para> - To avoid having a <literal><meta></literal>-tag inherited then you can simply - specify <literal>inherit="false"</literal> for the attribute, e.g. - <literal><meta attribute="scope-class" inherit="false">public abstract</meta></literal> - will restrict the "class-scope" to the current class, not the subclasses. - </para> - - </sect2> - - <sect2 id="toolsetguide-s2-3"> - <title>Basic finder generator</title> - - <para> - It is now possible to have <literal>hbm2java</literal> generate basic finders for - Hibernate properties. This requires two things in the <literal>hbm.xml</literal> - files. - </para> - - <para> - The first is an indication of which fields you want to generate finders for. You indicate - that with a meta block inside a property tag such as: - </para> - - <programlisting><![CDATA[<property name="name" column="name" type="string"> - <meta attribute="finder-method">findByName</meta> -</property>]]></programlisting> - - <para> - The finder method name will be the text enclosed in the meta tags. - </para> - - <para> - The second is to create a config file for hbm2java of the format: - </para> - - <programlisting><![CDATA[<codegen> - <generate renderer="net.sf.hibernate.tool.hbm2java.BasicRenderer"/> - <generate suffix="Finder" renderer="net.sf.hibernate.tool.hbm2java.FinderRenderer"/> -</codegen>]]></programlisting> - - <para> - And then use the param to <literal>hbm2java --config=xxx.xml</literal> where - <literal>xxx.xml</literal> is the config file you just created. - </para> - - <para> - An optional parameter is meta tag at the class level of the format: - </para> - - <programlisting><![CDATA[<meta attribute="session-method"> - com.whatever.SessionTable.getSessionTable().getSession(); -</meta>]]></programlisting> - - <para> - Which would be the way in which you get sessions if you use the - <emphasis>Thread Local Session</emphasis> pattern (documented in the Design Patterns - area of the Hibernate website). - </para> - - </sect2> - - <sect2 id="toolsetguide-s2-4"> - <title>Velocity based renderer/generator</title> - - <para>It is now possible to use velocity as an alternative rendering mechanism. - The follwing config.xml shows how to configure hbm2java to use its velocity renderer. - </para> - - <programlisting><![CDATA[ - <codegen> - <generate renderer="net.sf.hibernate.tool.hbm2java.VelocityRenderer"> - <param name="template">pojo.vm</param> - </generate> - </codegen>]]></programlisting> - <para> - The parameter named <literal>template</literal> is a resource path to the velocity macro file you want to use. - This file must be available via the classpath for hbm2java. Thus remember to add the directory where pojo.vm - is located to your ant task or shell script. (The default location is <literal>./tools/src/velocity</literal>) + A more detailed guide of <literal>hbm2net</literal> is available in + http://nhforge.org/blogs/nhibernate/archive/2009/12/12/t4-hbm2net-alpha-2.aspx </para> - - <para> - Be aware that the current <literal>pojo.vm</literal> generates only the most basic parts of the java beans. - It is not as complete and feature rich as the default renderer - primarily a lot of the <literal>meta</literal> tags - are not supported. - </para> - </sect2> - - </sect1> - - <sect1 id="toolsetguide-s3"> - <title>Mapping File Generation</title> - <para> - A skeletal mapping file may be generated from compiled persistent classes using - a command line utility called <literal>MapGenerator</literal>. This utility is part of - the Hibernate Extensions package. - </para> - - <para> - The Hibernate mapping generator provides a mechanism to produce mappings from - compiled classes. It uses Java reflection to find <emphasis>properties</emphasis> - and uses heuristics to guess an appropriate mapping from the property type. - The generated mapping is intended to be a starting point only. There is no way to produce - a full Hibernate mapping without extra input from the user. However, the tool does - take away some of the repetitive "grunt" work involved in producing a mapping. - </para> - - <para> - Classes are added to the mapping one at a time. The tool will reject - classes that it judges are are not <emphasis>Hibernate persistable</emphasis>. - </para> - - <para> - To be <emphasis>Hibernate persistable</emphasis> a class - </para> - - <itemizedlist spacing="compact"> - <listitem> - <para>must not be a primitive type</para> - </listitem> - <listitem> - <para>must not be an array</para> - </listitem> - <listitem> - <para>must not be an interface</para> - </listitem> - <listitem> - <para>must not be a nested class</para> - </listitem> - <listitem> - <para>must have a default (zero argument) constructor.</para> - </listitem> - </itemizedlist> - - <para> - Note that interfaces and nested classes actually are persistable by Hibernate, but - this would not usually be intended by the user. - </para> - - <para> - <literal>MapGenerator</literal> will climb the superclass chain of all added classes attempting - to add as many Hibernate persistable superclasses as possible to the same database table. - The search stops as soon as a property is found that has a name appearing on a list of - <emphasis>candidate UID names</emphasis>. - </para> - - <para> - The default list of candidate UID property names is: <literal>uid</literal>, <literal>UID</literal>, - <literal>id</literal>, <literal>ID</literal>, <literal>key</literal>, <literal>KEY</literal>, - <literal>pk</literal>, <literal>PK</literal>. - </para> - - <para> - Properties are discovered when there are two methods in the class, a setter and a getter, where the - type of the setter's single argument is the same as the return type of the zero argument getter, - and the setter returns <literal>void</literal>. Furthermore, the setter's name must start with the - string <literal>set</literal> and either the getter's name starts with <literal>get</literal> or - the getter's name starts with <literal>is</literal> and the type of the property is boolean. In - either case, the remainder of their names must match. This matching portion is the name of - the property, except that the initial character of the property name is made lower case if - the second letter is lower case. - </para> - - <para> - The rules for determining the database type of each property are as follows: - </para> - - <orderedlist spacing="compact"> - <listitem> - <para> - If the Java type is <literal>Hibernate.basic()</literal>, then the property is a - simple column of that type. - </para> - </listitem> - <listitem> - <para> - For <literal>hibernate.type.Type</literal> custom types and <literal>PersistentEnum</literal> - a simple column is used as well. - </para> - </listitem> - <listitem> - <para> - If the property type is an array, then a Hibernate array is used, and <literal>MapGenerator</literal> - attempts to reflect on the array element type. - </para> - </listitem> - <listitem> - <para> - If the property has type <literal>java.util.List</literal>, <literal>java.util.Map</literal>, or - <literal>java.util.Set</literal>, then the corresponding Hibernate types are used, but - <literal>MapGenerator</literal> cannot further process the insides of these types. - </para> - </listitem> - <listitem> - <para> - If the property's type is any other class, <literal>MapGenerator</literal> defers the decision - on the database representation until all classes have been processed. At this point, if the - class was discovered through the superclass search described above, then the property is - an <literal>many-to-one</literal> association. If the class has any properties, then it is - a <literal>component</literal>. Otherwise it is serializable, or not persistable. - </para> - </listitem> - </orderedlist> - - <sect2 id="toolsetguide-s3-1"> - <title>Running the tool</title> - - <para> - The tool writes XML mappings to standard out and/or to a file. - </para> - - <para> - When invoking the tool you must place your compiled classes on the classpath. - </para> - - <para> - <literal>java -cp </literal><emphasis>hibernate_and_your_class_classpaths</emphasis> - <literal>net.sf.hibernate.tool.class2hbm.MapGenerator</literal> <emphasis>options and - classnames</emphasis> - </para> - - <para> - There are two modes of operation: command line or interactive. - </para> - - <para> - The interactive mode is selected by providing the single command line argument - <literal>--interact</literal>. This mode provides a prompt response console. Using it you - can set the UID property name for each class using the <literal>uid=XXX</literal> command - where <literal>XXX</literal> is the UID property name. Other command alternatives are simply - a fully qualified class name, or the command done which emits the XML and terminates. - </para> - - <para> - In command line mode the arguments are the options below interspersed with fully qualified - class names of the classes to be processed. Most of the options are meant to be used - multiple times; each use affects subsequently added classes. - </para> - - <table frame="topbot"> - <title>MapGenerator Command Line Options</title> - <tgroup cols="2"> - <colspec colwidth="1*"/> - <colspec colwidth="2*"/> - <thead> - <row> - <entry>Option</entry> - <entry>Description</entry> - </row> - </thead> - <tbody> - <row> - <entry><literal>--quiet</literal></entry> - <entry>don't output the O-R Mapping to stdout</entry> - </row> - <row> - <entry><literal>--setUID=uid</literal></entry> - <entry>set the list of candidate UIDs to the singleton uid</entry> - </row> - <row> - <entry><literal>--addUID=uid</literal></entry> - <entry>add uid to the front of the list of candidate UIDs</entry> - </row> - <row> - <entry><literal>--select=</literal><emphasis>mode</emphasis></entry> - <entry>mode use select mode <emphasis>mode</emphasis>(e.g., - <emphasis>distinct</emphasis> or <emphasis>all</emphasis>) for subsequently - added classes</entry> - </row> - <row> - <entry><literal>--depth=<small-int></literal></entry> - <entry>limit the depth of component data recursion for subsequently added classes</entry> - </row> - <row> - <entry><literal>--output=my_mapping.xml</literal></entry> - <entry>output the O-R Mapping to a file</entry> - </row> - <row> - <entry><emphasis>full.class.Name</emphasis></entry> - <entry>add the class to the mapping</entry> - </row> - <row> - <entry><literal>--abstract=</literal><emphasis>full.class.Name</emphasis></entry> - <entry>see below</entry> - </row> - </tbody> - </tgroup> - </table> - - <para> - The abstract switch directs the map generator tool to ignore specific super classes so - that classes with common inheritance are not mapped to one large table. For instance, - consider these class hierarchies: - </para> - - <para> - <literal>Animal-->Mammal-->Human</literal> - </para> - <para> - <literal>Animal-->Mammal-->Marsupial-->Kangaroo</literal> - </para> - - <para> - If the <literal>--abstract</literal>switch is <emphasis>not</emphasis> used, all classes will - be mapped as subclasses of <literal>Animal</literal>, resulting in one large table containing - all the properties of all the classes plus a discriminator column to indicate which subclass is - actually stored. If <literal>Mammal</literal> is marked as <literal>abstract</literal>, - <literal>Human</literal> and <literal>Marsupial</literal> will be mapped to - separate <literal><class></literal> declarations and stored in separate tables. - <literal>Kangaroo</literal> will still be a subclass of <literal>Marsupial</literal> - unless <literal>Marsupial</literal> is also marked as <literal>abstract</literal>. - </para> - - </sect2> - </sect1> </chapter> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |