JudoScript.COM Design principles of Judo the sport and the language
HomeJudo LanguageJuSP PlatformJamaica Language 
Judo ReferenceJuSP ReferenceWiki/WeblogTutorials/PresentationsDownloadsGoodiesFeedback  
Book: The Judo Language 0.9
 








In this chapter:

Chapter 24. Hibernate ORM and HQL Scripting

By James Jianbo Huang

printer-friendly version
Synopsis: Hibernate is proven to be one of the best Object-Relational Mapping (ORM) frameworks for Java. Judo chooses to natively support Hibernate because object models written with Hibernate can be used in regular Java (and Judo), so that you can write Judo programs to use the same business logic as on the server to manipulate persistent data. Judo's native support for Hibernate include transactional features and query support with Hibernate Query Language (HQL) much the same way as Judo's JDBC scripting. Judo seamlessly supports scripting for both Hibernate versions 2 and 3, meaning that a same Judo program can be run with both Hibernate versions.

Enterprise applications typically persist data in relational databases. In object-oriented systems such as those written in Java, saving data equates to persist object states into SQL databases. One advantage of OOP is encapsulation, and hiding the database operations from the application code is only natural in an OO environment. ORM (Object-Relational Mapping) frameworks are designed to make this as easy, seamless and painless as possible. Mordern ORM frameworks, such as Hibernate, are very close to this ideal.

Hibernate has emerged to be one of the best ORM frameworks for Java. In Hibernate, you write an object models with totally normal Java objects with accompanying meta data in XML format, and the framework takes care of creating SQLs for persisting object state into the database. Hibernate also defines a query language, the Hibernate Query Language (HQL), for retrieving objects from database according to specific query conditions. Another important feature is, object models in Hibernate can be used both in containers and in plain Java software.

Judo chooses to natively support Hibernate, because Hibernate is clearly an ORM done right. Judo's Hibernate scripting support allows programmers to query the object model easily just like Judo's JDBC scripting (chapter 22. JDBC (SQL) Scripting). Also provided is a set of abstract commands for manipulating Hibernate persistent objects. This Hibernate scripting support is significant for systems implemented with Hibernate as its persistence layer: you can use Judo to manipulate data through the same object model that the system uses, so the data integrity and business rules are best maintained.

 
Introduction to Hibernate and HQL

Object-oriented systems, such as those written in Java, comprise of graphes of objects. Some objects will disappear some time prior to the demise of the running JVM; others will be persisted and can be reinstated later on. By far, the most popular persistence stores for object data are relational databases, because of the simplicity, well-established SQL support and the plethora of reporting and data mining tools avaiable. However, relational models and object models are distinctly different; mapping objects states to and from relational databases takes a lot of work, which typically means writing a lot of SQL code and JDBC calls. Numerous efforts have been made to automate this object-relational mapping, yielding a special breed of infrastructural softwared called object-relational mapping (ORM) framework. ORM frameworks reduce or even eliminate the need of any hand-written SQL statements, and also offer many options for better system design and performance.

Hibernate is one of the ORM frameworks. It is one of the least intrusive object mapping mechanism and does automatic dirty check. The Hibernate framework and the code using it can be run in both managed containers and unmanaged environment. It provides enough facilities to address the complicated problem of ORM, yet are mostly intuitive enough for the causes. It has a versatile query language, the Hibernate Query Language or HQL for short. Hibernate is undoubtedly one of the best Java ORM solutions, and Judo chooses to support it natively, so that users can easily script an object model written in Hibernate to perform tasks consistent with systems that are built on top of the same object model.

A Simple Example of Object Mapping

Hibernate, being an ORM framework, deals with three parties: Java classes, relational database schema and the mapping between the two defined by Hibernate. For each Java classs, a descriptor is required for each Java class. This descriptor can be a separate XML document (typically with the extension of .hbm.xml), or as annotational tags within the Java source file. Hibernate provides tools to generate one party from the other; for instance, from a mapping descriptor file, you can generate the corresponding Java source file and database schema, or generate the descriptor file from a Java class source file.

Let's take a look at a simplest object model, that is, one that just contains a single class called TestSimpleTypes. The mapping descriptor file is:

Listing 24.1 TestSimpleTypes.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
  "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
  "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping>
  <class name="TestSimpleTypes" discriminator-value="N">
    <id name="id" type="long"> <generator class="native"/> </id>
    <property name="theFloat"   type="float"/>
    <property name="theString"  type="java.lang.String"/>
    <property name="theDate"    type="java.util.Date"/>
  </class>
</hibernate-mapping>

Run the hbm2java tool, and the Java source file is generated:

Listing 24.2 TestSimpleTypes.java
import java.util.Date;
import org.apache.commons.lang.builder.ToStringBuilder;

/** @author Hibernate CodeGenerator */
public class TestSimpleTypes implements java.io.Serializable
{
    private Long id;
    private Float theFloat;
    private String theString;
    private Date theDate;

    public TestSimpleTypes(Float theFloat, String theString, Date theDate) {
        this.theFloat = theFloat;
        this.theString = theString;
        this.theDate = theDate;
    }

    public TestSimpleTypes() {}

    public Long getId() { return this.id; }
    public void setId(Long id) { this.id = id; }

    public Float getTheFloat() { return this.theFloat; }
    public void setTheFloat(Float theFloat) { this.theFloat = theFloat; }

    public String getTheString() { return this.theString; }
    public void setTheString(String theString) { this.theString = theString; }

    public Date getTheDate() { return this.theDate; }
    public void setTheDate(Date theDate) { this.theDate = theDate; }

    public String toString() {
        return new ToStringBuilder(this).append("id", getId()).toString();
    }
}

Note that the Java class doesn't have to implement any Hibernate-specific interfaces! Because of this, Hibernate is deemed one of the least intrusive ORM framework. This generated code simply contains property getters and setters. You can add business logic methods and other convenience methods, and there are ways to define composite or calculated properties; this falls in the realm of Hibernate ORM practices and is out of the scope of this chapter.

Compile the Java source file and bundle the descirptor hbm.xml file in the same classpath, there you have a working Hibernate object model.


Key Hibernate API Classes and Interfaces

Once you have the object model ready, you can use Hibernate to retrieve persistent objects from database and write the object state back to database via calls to Hibernate APIs.

The reason Judo provides native support for any domain is to hide the details of the domain APIs. While this holds true with Hibernate scripting as well, it is a little different. Because Hibernate object models are predominantly used in Java systems, understanding the API itself is a necessity to anyone who uses Hibernate. Here we summarize the most important Hibernate API classes and interfaces for using Hibernate object models. In the rest of this chapter, we will refer to these classes and interfaces when discussing Judo's Hibernate scripting support.

Hibernate versions and API names
Hibernate version 2 API used prefix of net.sf.hibernate; later versions use the prefix of org.hibernate. Judo can script both and you are not exposed with this issue. In this documentation, however, we have to occasionally refer to the Hibernate API classes and interfaces. For the convenience of this discussion, we simply use the prefix of org.hibernate, but keep in mind that if you are working with Hibernate version 2, the prefix should be net.sf.hibernate.

In Java Hibernate programs, these are the most basic classes and interfaces:

  • org.hibernate.cfg.Configuration
  • org.hibernate.SessionFactory
  • org.hibernate.Session
  • org.hibernate.Transaction

For Hibernate transactions, these classes and interfaces are critical:

  • org.hibernate.Query
  • org.hibernate.Criteria
  • org.hibernate.Lock

In Hibernate object models, you may very likely encounter user-defined types, which are implementations of one of these interfaces:

  • org.hibernate.UserType
  • org.hibernate.CompositeUserType

There are other classes and interfaces in Hibernate API that allow various kinds of extensions to the framework, which are not that important to our purpose of scripting Hibernate object models.


Set-Up and Initialization of Hibernate

For any applications using Hibernate, the Hibernate environment must be initialized once. This means to initialize an instance of the Configuration, from which to derive a singleton instance of SessionFactory. Hibernate object persistence is done in units of work called sessions, represented by the Session interface. Each session is created by the session factory.

The Hibernate configuration is extremely important; it contains information about the whole ORM environment as well as the object model itself. There are two ways to configure Hibernate. The first way is to use initialization properties, which can be either from System.getProperties() or stored in a hibernate.properties file in the classpath. The second way is the more versatile configraution XML document, hibernate.cfg.xml, also in the classpath. Using hibernate.cfg.xml, you can contain object model as well; if you use properties, you would have to programmatically add each class in the object model via Configuration.addResource() or Configuration.addClass() calls.

Commonly-used Hibernate configuration attributes
The most important information to configure is the database connection. In standalone applications, you probably need these attributes:

  • hibernate.connection.driver_class
  • hibernate.connection.url
  • hibernate.connection.username
  • hibernate.connection.password
  • hibernate.connection.pool_size
  • hibernate.dialect
If the application runs inside an application server, you may want to obtain a data source for database connection:
  • hibernate.connection.datasource
  • hibernate.jndi.url
  • hibernate.jndi.class
There are many options for database connections, caching and others. Some of the interesting attributes are:
  • hibernate.show_sql
  • hibernate.hbm2dll.auto
Hibernate provides good documentation, and it would be beneficial to browse all the attributes at least once.

Steps of using Hibernate in Java
To use Hibernate in a Java applications, including Judo programs, these are the steps:

  1. Define the object model by creating Java class source files and their accompanying hbm.xml files.
  2. Decide on the parameters for the Hibernate environment and create configuration files.
  3. At runtime, initialize the Configuration instance with the configuration information and register the object model classes.
  4. Derive a SessionFactory singleton.
  5. Obtain a Session to carry out a unit of work of CRUD persistent objects, in one or more transactions.



 
Hibernate Scripting

Judo provides a number of abstract constructs to make it very easy to script objects in Hibernate object models. These are mechanisms for initializing and accessing Hibernate environment:

  • The hib::setup statement:
    for configuring Hibernate.
  • The hib::addClass and hib::addResource statements:
    for programmatically adding object model classes.
  • The hib::get function:
    for returning Hibernate system objects such as configuration, session factory and the current session object, in case Java-style API manipulations are intended.

Judo provides these mechanisms for persisting objects:

  • The hib::get( JavaClass, ObjectID [ , lock ] ) function:
    to get a persistent object from the database.
  • The hib::save, hib::update, hib::saveOrUpdateCopy, hib::delete and hib::lock and hib::unlock functions:
    for persist object states to the database.
  • The hib::txBegin, hib::txEnd and hib::txAbort statements:
    for transactions that may involve multiple steps of object manipulations.

Judo provides these mechanisms for HQL querying and deleting multiple objects:

  • The hib::query, hib::iterate and hib::delete statements:
    for HQL scripting. They are syntactically similar to the JDBC scripting db::query statement.

Set-Up and Initialization of Hibernate

The hib::setup statement abstracts the Hibernate configuration. You can specify everything in this single statement. Its syntax is:

Hibernate_Setup ::= hib::setup [ attributes ] [ ( JavaClassName | STRING_LITERAL ),* ] ;
attributes ::= ( ( PROPERTY_NAME = Expr ),* )

Let's look at an example.

import com.foo.bar.Auction.*;

hib::setup (
    hibernate.connection.url      = 'jdbc:mysql://localhost/test',
    hibernate.connection.username = 'james',
    hibernate.connection.password = 'james',
    hibernate.hbm2ddl.auto        = 'update',
    hibernate.show_sql            = true,
    judoscript.echo               = true  // echo the eventual config values
  )

  'com/foo/bar/Auction/Item',   // add a resource
  com.foo.bar.Auction.Category, // add a class with qualified class name
  Bid                           // add a class qualified via the import.
;

The attributes in the parentheses are the same as those in the hibernate.proeprties file; the Java class names and/or mapping hbm.xml files are listed at the end. Look closely at the database connection attributes, and you may find that there are some important attributes missing, such as hibernate.connection.driver_class and hibernate.dialect. This is because Judo knows many relational databases; based on the JDBC URL , Judo can figure out the driver class (see JDBC Drivers) and Hibernate dialects. The ultimate properties used by Hibernate may have more attributes than what are specified in the hib::setup statement. Judo provides an extra boolean attribute, judoscript.echo; when it is , Judo will print out all the attributes before Hibernate is actually initialized. So when you run it, you may first see something like this:

[hib::setup] hibernate.connection.username = james
[hib::setup] judoscript.echo = true
[hib::setup] hibernate.connection.password = james
[hib::setup] hibernate.dialect = net.sf.hibernate.dialect.MySQLDialect
[hib::setup] hibernate.connection.url = jdbc:mysql://localhost/test
[hib::setup] hibernate.connection.driver_class = com.mysql.jdbc.Driver
[hib::setup] hibernate.hbm2ddl.auto = update
[hib::setup] judoscript.hibernate.version = 2

The last property, judoscript.hibernate.version, is a Judo internal indicator. In the above output, it is "2" because we ran with Hibernate version 2. Judo figures out the Hibernate version based on the classes it founds; if Hibernate version 3 classes are in the classpath instead, it would yield the following result:

[hib::setup] hibernate.connection.username = james
[hib::setup] judoscript.echo = true
[hib::setup] hibernate.connection.password = james
[hib::setup] hibernate.dialect = org.hibernate.dialect.MySQLDialect
[hib::setup] hibernate.connection.url = jdbc:mysql://localhost/test
[hib::setup] hibernate.connection.driver_class = com.mysql.jdbc.Driver
[hib::setup] hibernate.hbm2ddl.auto = update
[hib::setup] judoscript.hibernate.version = 3

You can choose to store configuration information in the configuration file instead. For example, the following statement initializes Hibernate:

hib::setup;

In this case, you need to specified everything in a hibernate.cfg.xml document that can be found in the classpath, which contains something like this:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
  "-//Hibernate/Hibernate Configuration DTD 2.0//EN"
  "http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd">
<hibernate-configuration>
  <session-factory name="java:/hibernate/HibernateFactory">
    <property name="show_sql">true</property>
    <property name="connection.datasource">java:/comp/env/jdbc/AuctionDB</property>
    <property name="dialect">org.hibernate.dialect.MySQLDialect"</property>

    <mapping resource="auction/Item.hbm.xml"/>
    <mapping resource="auction/Category.hbm.xml"/>
    <mapping resource="auction/Bid.hbm.xml"/>
  </session-factory>
</hibernate-configuration>

You can also put configuration attributes in the hibernate.properties file, in which case all the classes in the object model must be specified explicitly in hib::setup. All attributes must be specified, such as hibernate.connection.driver_class and hibernate.dialect.

Programmatically add classes and/or resources
There may be situations where you prefer to programmatically add classes of the object model to the Hibernate environment instead of declaring them in hib::setup statement. Judo provides two functions for this purpose: hib::addClass() and hib::addResource(). For instance, perhaps you want to add all the hbm.xml mapping files in a folder within a jar file:

hib::setup;

listFiles '*.hbm.xml' in 'myobjmdl.jar' recursive
{
  hib::addResource $_; // $_ holds the current file path
}

Hibernate system objects
After initialization, Judo maintains a singleton of Configuration and a SessionFactory instances. When any of the persisting operations (discussed later) are invoked, a new session is created (if it doesn't already exist); this session will be there until hib::close is called.

The hib::get() function can take an argument of "config", "factory or "session" and return one of these Hibernate system objects. For example, you may want to get the session object and invoke its criteria API to perform a query-by-example (QBE) operation:

import org.hibernate.expression.Example;

hib::setup;

exampleUser = new java::User;
exampleUser.firstName = 'Max';

sess = hib::get('session');
crit = sess.createCriteria(java::User);
crit.add( Example::create(exampleUser) );
result = crit.list(); // result is a List.

for x in result {
  println x.firstName, ' ', x.lastName;
}
This example is almost purely Java scripting except it gets the session object via hib::get().

Note that hib::get() function is dual-purpose: it can also be used to retrieve individual persistent objects from database, as you will see in the next section.


Support for Object Persistence and Transactions

Once Hibernate is initialized properly, you can create and manipulate instances in the object model using the Hibernate functions and operators.

Hibernate sessions and transactions
As we know, all the object persistence operations in Hibernate occur within a session. In Judo, a session is started automatically whenever any persisting operation starts, per each thread. The session is open until hib::close is called.

More accurately, Hibernate object persisting operations happen in transactions, and multiple transactions can happen in a session. In Judo, you can start a transaction via a hib::txBegin call, and commit and finish it via a hib::txEnd call, or roll back the changes by a hib::txAbort call. If a transaction is not started for a session, operations are in the auto-commit mode, where each operation starts its own transaction, commits it once done. Because the session instance is per-thread, there can be only one transaction per session at any moment.

Persistent object life-cycles and manipulation
In Hibernate, persistent objects can be in one of the following states: transient, persistent and detached. An object is in the transient state when it is either newly created, or deleted. An object with a valid database identifier is said to be persistent. Persistent objects are associated with a Session instnace; some API calls can disassociate persistent instances from the Session, and such instances are said to be in the detached state. Detached instances' changes will not be automatically picked up unless they are explicitly updated by a Session.

In Judo, Hibernate persistent objects' life-cycles are managed with these built-in functions and operators:

  • hib::get( InstanceClass , Identifier [ , LockMode ] ):
    to get a persistent instance from the database, and optionally lock the instance.
  • hib::save Instance:
    to save a newly created instance. If the current thread is in a transaction, the change is not committed until the transaction commits; otherwise, this call auto-commits.
  • hib::update Instance:
    to update a persistent instance. If the current thread is in a transaction, the change is not committed until the transaction commits; otherwise, this call auto-commits.
  • hib::saveOrUpdateCopy Instance:
    to update a persistent instance or insert a detached instance. If the current thread is in a transaction, the change is not committed until the transaction commits; otherwise, this call auto-commits.
  • hib::delete Instance:
    to delete a persistent instance. If the current thread is in a transaction, the change is not committed until the transaction commits; otherwise, this call auto-commits.
  • hib::lock Instance , LockMode:
    to lock a persistent instance.
  • hib::unlock Instance:
    to unlock a locked instance. This is equivalent to calling hib::lock(instance, "none") or hib::lock(instance, null).

If you have worked with the Hibernate API, you probably recognize that most of them are methods of the Session interface. This is indeed true, as these functions and operators are delegates to the methods of the underlying per-thread Session instance. All parameters are natural to the API, except for the LockMode used in hib::get() and hib::lock(), which is normally a case-insensititive name of "none", "read", "upgrade", "upgrade_nowait" and "write", or an instance of org.hibernate.LockMode (such as one of its static final instances like NONE, READ, UPGRADE, UPGRADE_NOWAIT and WRITE).

Let's take a look at an example. The following script uses the simple object model we saw earlier, which comprises of a single class, TestSimpleTypes.

Listing 24.3 SimplestORM.judo
//
// 1. First of all, initialize the Hibernate environment using MySQL.
//
hib::setup (
    hibernate.connection.url      = 'jdbc:mysql://localhost/test',
    hibernate.connection.username = 'james',
    hibernate.connection.password = 'james',
    hibernate.hbm2ddl.auto        = 'update',
    judoscript.echo               = true
  )

  TestSimpleTypes
;

//
// 2. Create a new object, and save it.
//
x = new java::TestSimpleTypes(10.5, 'abcdefg', Date());
println 'Before save: x.id = ', x.id;
hib::save(x);
println 'After save: x.id = ', x.id;

//
// 3. Modify the object and update it.
//
x.theFloat = 100.8;
hib::update(x);
println 'Updated x.';

//
// 4. Find that object.
//
y = hib::get(java::TestSimpleTypes, x.id);
println 'Found: y.id = ', y.id, '  y.theFloat = ', y.theFloat;

//
// 5. Delete the object.
//
hib::delete y;
z = hib::get(java::TestSimpleTypes, y.id);
if (z != null)
  println 'Found: z.id = ', z.id;
else
  println 'Object[id=', y.id, '] has been deleted.';

//
// 6. Reinstate the object (obtains a different ID).
//
println 'Re-save y... currently, y.id = ', y.id;
hib::saveOrUpdateCopy y; // put it back in.
println 'Now, y.id = ', y.id;

In this script, we conduct six experiments. The first experiment is for hib::setup, where we simply specify a MySQL database connection, and turn on the judoscript.echo option to see the "real" properties at runtime. The output for this part is:

[hib::setup] hibernate.connection.username = james
[hib::setup] judoscript.echo = true
[hib::setup] hibernate.connection.password = james
[hib::setup] hibernate.dialect = org.hibernate.dialect.MySQLDialect
[hib::setup] hibernate.connection.url = jdbc:mysql://localhost/test
[hib::setup] hibernate.connection.driver_class = com.mysql.jdbc.Driver
[hib::setup] hibernate.hbm2ddl.auto = update

The second experiment creates a new instance and saves it to the database. We simply print out the instance's identifier before and after the save, and you can see the identifier is filled in during the persisting process:

Before save: x.id =
After save:  x.id = 1

The third experiment then changes one of its property and updates it in the database. Then, the forth experiment gets that instance from the database and verifies that the changed property is indeed as expected:

Updated x.
Found: y.id = 1  y.theFloat = 100.80000305175781

The fifth experiment deletes that instance (note this is auto-committed), and then tries to get it from the database, which should return null:

Object[id=1] has been deleted.

By now, the instance referenced by y is in transient state, that is, it does not exist in the database, and its identifier, though not null, is bogus. Finally, the sixth experiment calls hib::saveOrUpdateCopy to save it again into the database. We print out its identifier for proof:

Re-save y... currently, y.id = 1
Now, y.id = 2

Summary
To summarize, Judo provides the aforementioned statements, functions and operators to hide the details of manipulating Hibernate persistent objects. These operations are terse, intuitive and convenient, and the resultant code is much less noisy than the Java counterpart.

Many of the object life-cycle management functions and operations are delegates to the org.hibernate.Session methods. But the org.hibernate.Session has more methods that you may want to call, and you may even need to call methods of the org.hibernate.SessionFactory and org.hibernate.cfg.Configuration instances. Judo doesn't stop you from doing this: you can get these objects via a call to hib::get('session'), hib::get('factory') or hib::get('config'). Such API calls are considered far less likely to happen as compared to the hib:: operations. Citing the 80-20 rule, Judo's Hibernate scripting makes it easy for the >80% chance of sripting Hibernate while leaving it possible for the <20% chance of Hibernate API calls.


Support for HQL and Multiple Object Deletion

Hibernate defines a SQL-like object query language, Hibernate Query Language (HQL for short), to find a collection of objects from the database or from a collection of objects. The found objects can be returned or deleted. HQL can also return a collection of values rather than objects; this is sometimes called report queries. Like, JDBC, the Hibernate HQL API allows users to dynamically bind parameters to a query.

Judo supports HQL scripting in a way similar to chapter 22. JDBC (SQL) Scripting. Judo provides a unified syntax for querying and deleting objects using HQL:

HQL ::= ( hib::query | hib::iterate | hib::delete ) [ IDENTIFIER ] [ options ] : HQL ; [ with BindVariableList ; ]
options ::= ( ( from | limit | in ) Expr )*
BindVariableList ::= ( IDENTIFIER [ : HibernateType ] = Expr ),*

In this unitified syntax, the options are for pagination and query in a collection; they obviously don't apply to hib::delete. The hib::iterate is functionally the same as hib::query, but Hibernate does the query in two steps: for non-report queries, it first finds the identifiers of entities and then fetches the entities on demand; this is primarily to allow applications to take advantage of the second-level cache. Let's see an example of query.

Listing 24.4 Queries.judo
hib::setup (
    hibernate.connection.url      = 'jdbc:mysql://localhost/test',
    hibernate.connection.username = 'james',
    hibernate.connection.password = 'james',
    hibernate.hbm2ddl.auto        = 'update'
  )

  TestSimpleTypes
;

//
// Query for objects:
//
hib::query qry:  // or hib::iterate.
  from TestSimpleTypes o where o.id > 9 and o.id < 15
;
// now, qry is a List of TestSimpleTypes's --
for o in qry {
  println o;
}

//
// Report query:
//
hib::query qry:
  select o.id, o.theFloat, o.theString from TestSimpleTypes o
  where o.id > :startIdx and o.id < :endIdx
; with startIdx:Long = 9, endIdx:Long = 15;

// now, qry is a List of Object[] --
for o in qry {
  println o;
}

The first query returns a collection of TestSimpleTypes instances. It is the same as:

hib::query qry:  // or hib::iterate.
  select o from TestSimpleTypes o where o.id > 9 and o.id < 15
;

The second query is the so-called report query that returns a collection of Object[] arrays. This one actually uses bind variables, startIdx and endIdx; we will discuss bind variables later. The running result is:

TestSimpleTypes@ff94b1[id=10]
TestSimpleTypes@7c3885[id=12]
TestSimpleTypes@162e295[id=14]
[10,100.8,abcdefg]
[12,100.8,abcdefg]
[14,100.8,abcdefg]

The reason that the ids are all even numbers is because the operations done in code listing 24.3.

Delete objects via HQL
You can delete objects with the same HQL syntax:

Listing 24.5 DeleteObjects.judo
hib::setup (
    hibernate.connection.url      = 'jdbc:mysql://localhost/test',
    hibernate.connection.username = 'james',
    hibernate.connection.password = 'james',
    hibernate.hbm2ddl.auto        = 'update'
  )

  TestSimpleTypes
;

//
// Delete objects:
//
hib::delete:
  from TestSimpleTypes o where o.id > :startIdx and o.id < :endIdx
; with startIdx:Long = 11, endIdx:Long = 13;

//
// Verify:
//
hib::query qry:
  select o.id, o.theFloat, o.theString from TestSimpleTypes o
  where o.id > :startIdx and o.id < :endIdx
; with startIdx:Long = 9, endIdx:Long = 15;

for o in qry {
  println o;
}

And the result is:

[10,100.8,abcdefg]
[14,100.8,abcdefg]

Bind variables
If you have worked with JDBC scripting (chapter 22. JDBC (SQL) Scripting), then bind variable is not a stranger. In Judo JDBC scripting, you can embed use question marks or names prefixed with colons : to represent bind variables with SQL statements. When the SQLs are run, you can bind variables to them with index numbers (starting at 1) or by name. The SQL binding variables can be assigned with a type; if no type specified, by default it is VARCHAR.

For HQL statements, it is slightly different. First of all, only named bind variables are supported in HQL statements. Secondly, the bind variable type must always be specified. The types are those defined by Hibernate, which include built-in types that are mostly Java and JDBC types, or custom types. Keep in mind that, with Judo's Java scripting support (chapter 11. Java Scripting), you can use import just like in Java, and also, java.lang.*, java.util.* and java.io.* are imported automatically. For instance, in code listing 24.4, the second query bound values to startIdx and endIdx with type Long, which is really java.lang.Long.



 
Working with Hibernate Object Models   to be done

In this section, we are going to explore some of the common situations in using Hibernate. TODO: to be done.

Mapping Types


Mapping Entity and Value Types


Mapping Class Inheritance

Table per concrete class
.

Table per class hierarchy
.

Table per subclass
.


Mapping Associations

One-to-one relationship
.

Many-to-one unidirectional relationship
.

Many-to-one bidirectional relationship
.

Many-to-many relationship
.

Polymorphic associations
.



 
Summary

Why Judo support a proprietary API to such an extent for Hibernate? We believe that Hibernate is one of the best solutions in the problem domain of ORM, and it has a promising future. Hibernate may be somehow absorbed into some standards, at which time Judo will evolve accordingly to support that standard. For now, natively support Hibernate seems good enough.

Judo's native Hibernate support makes much sense. One of the biggest selling points of Hibernate is that object models written in Hibernate can be used in and out of containers; the same object model can be used in a web application and by a command-line tool, say. Judo is designed to be a powerful data manipulation tool; by using Hibernate object models (rather than, say, using raw SQL) in Judo programs, business rules and data integrity will be easily maintained throughout the system. Conversely, during system design phase, Judo is an ideal tool for prototyping and testing the object model, which may ultimately lead to automated testing package for the object model, probably as a part of the overall system test suite.


 
back to top
 



Copyright © 2001-2005 JudoScript.COM. All Rights Reserved.