License     Codehaus     OpenEJB     OpenJMS     OpenORB     Tyrex     

Old releases
  General
  Release 1.3
  Release 1.3rc1
  Release 1.2

Main
  Home
  About
  Features
  Download
  Dependencies
  Reference guide
  Publications
  JavaDoc
  Maven 2 support
  Maven 2 archetypes
  DTD & Schemas
  Recent HTML changes
  News Archive
  RSS news feed
  Project Wiki

Development/Support
  Mailing Lists
  SVN/JIRA
  Contributing
  Support
  Continuous builds
  Prof. services

Related projects
  Spring ORM support
  Spring XML factories
  WS frameworks

XML
  XML

XML Code Generator
  XML Code Generator

JDO
  Introduction
  First steps
  Using JDO
  JDO Config
  Types
  JDO Mapping
  JDO FAQ
  JDO Examples
  JDO HOW-TOs
  Tips & Tricks
  Other Features
  JDO sample JAR

Tools
  Schema generator

Advanced JDO
  Caching
  OQL
  Trans. & Locks
  Design
  KeyGen
  Long Trans.
  Nested Attrs.
  Pooling Examples
  LOBs
  Best practice

DDL Generator
  Using DDL Generator
  Properties
  Ant task
  Type Mapping

More
  The Examples
  3rd Party Tools
  JDO Tests
  XML Tests
  Configuration
 
 

About
  License
  User stories
  Contributors
  Marketplace
  Status, Todo
  Changelog
  Library
  Contact
  Project Name

  



Castor JDO - Advanced features

Documentation Author(s):
Werner Guttmann

Reference: The Java Data Objects API


Introduction
Caching
Dependent and related relationships
Different cardinalities of relationship
Lazy Loading
    1:1 relations
    1:M and M:N relations
Multiple columns primary keys
Callback interface for persistent operations


Introduction

As explained at the introduction to Castor JDO, Castor has support for many advanced features such as caching, depend relations, inheritance, polymorphism, etc. The below sections detail these features, as their understanding is required to use Castor JDO in a performant and secure way.

Caching

All information related to caching and related concepts supported by Castor has been consolidated into one place, and is available here.

Dependent and related relationships

Castor distinguishes the relationship of two objects as dependent or related, and maintains the life cycle independently for the two types of relationships. Starting from Castor 0.9, the developer can explicitly define a dependent relationship in the mapping file.

When using independent relations, related objects’ life cycle is independent of each other, meaning that they have to be created, removed and updated (for long transaction) independently.

When using dependent relations, one data object class must be declared as depends on one other data object class in the mapping file, and such an object is called a dependent data object class. A data object class without depends declared in the mapping is called a master object. A master object can be depended upon by zero or more dependent data object class.

As of Castor 0.9, a dependent object class can be related to other master data object classes including extended classes, but cannot depend on more than one master class.

If an object class declared as depends on another class, it may not be created, removed or updated separately. Attempting to create, remove or update a dependent object will result in ObjectNotPersistcapableException. Note that Castor doesn'’t allow a dependent object instance to change its master object instance during a transaction. Each dependent object can have only one master object. Both dependent and master objects must have identities, and may or may not make use of key-generators.

Here is the DTD for declaring dependent object:

<!ATTLIST class     name ID  #REQUIRED
          extends   IDREF    #IMPLIED
          depends   IDREF    #IMPLIED
          identity  CDATA   #IMPLIED
          access    ( read-only | shared | exclusive | db-locked )  "shared"
          key-generator   IDREF #IMPLIED

For example,

<mapping>
    <class name="com.xyz.MyDependentObject"
        depends="com.xyz.MyObject">
        ...
    </class>
</mapping>

declares the data object class com.xyz.MyDependentObject as a dependent upon class com.xyz.MyObject.

Different cardinalities of relationship

Castor supports different cardinalities of relationship, namely one-to-one, one-to-many, and many-to-many. Many-to-many relationship must be related rather than dependent, because each dependent object can have only one master object.

Many-to-many requires a separate table for storing the relations between two types of objects. Many-to-many introduces two attributes, namely many-key and many-table that reside in the <sql> element which is a sub-element of the <field> element. For all many-to-many relations, a many-table must be specified. If the column name of the primary key of the class is different from the foreign keys columns of the class in the relation tables, then the relation table columns can be specified using the many-key attributes. Similarly, if the column name of the primary key of the related class is different from the foreign key columns of the related class, then the relation table columns can be specified using the name attribute.

The many-table is used to store relations in a separate table

<mapping>
    <class>
        <field>
            <sql many-key="#OPTIONAL" name="#OPTIONAL"
                 many-table="#REQURIED">
        </field>
    </class>
</mapping>

So, for example, if the SQL table is the following,

employee_table
id name salary
1482 Smith, Bob $123,456
628 Lee, John $43,210
1926 Arnold, Pascal $24,680
department_table
id name comment
3 Accounting
7 Engineering The very important department. :-)
employee_department
e_id d_id
.... ....

Then, the mapping for employee data object would look like this

<mapping>
    <class name="com.xyz.Employee" identity="id">
        <map-to table="employee_table"/>
            <field name="id" type="integer">
                <sql name="id"/>
            </field>
            <field>
                <sql many-table="employee_department"
                     many-key="e_id" name="d_id"/>
            </field>
            <field name="salary">
                <sql name="salary" type="integer">
            </field>
    </class>
</mapping>

Lazy Loading

As of release 0.9.6, Castor has full support for lazy loading object instances referenced as part of all relation types currently supported:

-1:1 relations
-1:m relations
-M:N relations.

1:1 relations

As of release 0.9.6, Castor supports lazy-loading of 1:1 relations. Imagine the following class mapping:

<mapping>
    <class name="com.xzy.Department">
       ...
       <field "employee" type="com.xyz.Employee" lazy="true" />
       ...
    </class>
</mapping>

Per definition, when an instance of Department is loaded through e.g. Database.load(), Castor will not (pre-)load the Employee instance referenced (as such reducing the size pf the initial query as well as the size of the result set returned). Only when the Emplyoee instance is accessed through Department.getEmployee(), Castor will load the actual object into memory from the persistence store.

This means that if the Employee instance is not accessed at all, not only will the initial query to load the Department object have had its complexity reduced, but no performance penalty will be incurred for the additional access to the persistence store either.

1:M and M:N relations

The elements in the collection are only loaded when the application asks for the object from the collection, using, for example, iterator.next(). The iterator in Castor’s lazy collection is optimized to return a loaded object first.

In the mapping file, lazy loading is specified in the element of the collection’s <field>, for example,

<mapping>
    <class name="com.xzy.Department">
       ...
        <field name="employee" type="com.xyz.Employee" lazy="true"
               collection="collection"/>
    </class>
</mapping>

declares that the collection of type Employee in a Department is lazy loaded.

If lazy loading is specified for a field of a class, Castor will set the field with a special collection which contains only the identities of the objects. Because of that, it requires the data object to have the method setDepartment( Collection department) in the data object class which was not required in previous versions.

Note
Please note that currently only the java.util.Collection type is supported.

Multiple columns primary keys

The support of multiple column primary keys (also called compound primary keys) was another major enhancement added into Castor 0.9. Specifying multiple column primary keys is simple and straightforward, in the mapping file,

<mapping>
    <class name="com.xyz.MyObject" identity="firstName lastName">
        <field name="firstName" type="string">
           <sql name="fname"/>
        </field>
        <field name="lastName" type="string">
           <sql name="lname"/>
        </field>
           ...
    </class>
</mapping>

Multiple column primary keys work with both master and dependent objects, all cardinalities of relationship, including one-to-one, one-to-many and many-to-many, as well as lazy loading.

However, multiple column primary keys should only be used to adhere to an existing database design, not when designing a new database. In general, it is not a good idea to use an identity or identities which can be modified by the user, or which contain application-visible data. For example, if the system allows the user name to be changed, using user name as identity is highly discouraged, as this practice can require a major data migration to a new schema to update all foreign keys to adhere to a new primary key structure, should the user name no longer be adequate as a primary key. It should be noted that Castor doesn’t support identity change, as specified in the ODMG 3.0 specification. So, primary keys changes are almost certainly a large trade off between data integrity and performance. Well chosen primary keys are usually single (not multiple) column numeric or character fields for the reasons outlined above, as well as performance, as joining operations are faster for single column primary keys.

Callback interface for persistent operations

For the various persistence operations as available through the Database interface, Castor JDO provides a callback interface that informs the implementing class on events taking place related to selected persistence operations.

Once your entity class implements the Persistence interface, you'll have to provide implementations for the following methods (with their respective semantics described next to them):

MethodDescription
jdoAfterCreate() Indicates that an object has been created in persistent storage.
jdoAfterRemove() Indicates that an object has been removed from persistent storage.
jdoBeforeCreate() Indicates that an object is to be created in persistent storage.
jdoBeforeRemove() Indicates that an object is to be removed from persistent storage.
jdoLoad() Indicates that the object has been loaded from persistent storage.
jdoPersistent(Database) Sets the database to which this object belongs when this object becomes persistent.
jdoStore() Indicates that an object is to be stored in persistent storage.
jdoTransient() Indicates the object is now transient.
jdoUpdate() Indicates that an object has been included to the current transaction by means of db.update() method (in other words, at the end of a "long" transaction).
 
   
  
   
 


Copyright © 1999-2005 ExoLab Group, Intalio Inc., and Contributors. All rights reserved.
 
Java, EJB, JDBC, JNDI, JTA, Sun, Sun Microsystems are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and in other countries. XML, XML Schema, XSLT and related standards are trademarks or registered trademarks of MIT, INRIA, Keio or others, and a product of the World Wide Web Consortium. All other product names mentioned herein are trademarks of their respective owners.