|  |  |  | 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 FAQ Castor's relation to other specifications Does Castor JDO comply with the SUN JSR-000012 specification? Is Castor JDO better than EJB CMP? XML related questions Is it possible to make XML marshalling transactionally using Castor? Is it possible to do queries on a XML file using Castor? Technical questions Where can I find some examples to start with? I have encountered problems using Sun JDBC-ODBC bridge with Castor... My get-method for the Collection of dependent objects returns null. Why? Should my JDO classes implement some special interface? Can Castor automatically create/remove related objects? Is Castor JDO using any connection pooling mechanism to improve the overall performance? I am getting ClassNotFoundException for my JDO class, but it is in the class path. Why? I am getting exception 'the class ... is not persistence capable...'. Why? I call db.remove() on the dependent object and commit, but this doesn't work... How should I represent string/date/boolean literals in OQL query? I get 'java.lang.AbstractMethodError: getBigDecimal' for numeric fields. Why? Does Castor support both one-way and two-way relationships? I have an object that holds a relation to itself. Does Castor support this? Why do I get an ObjectModifiedException when trying to commit a transaction? I'm receiving a java.sql.SQLException: ORA-01461 Castor and performance caches Sometimes long transaction fails: on update() it is thrown ObjectModifiedException. Why? Can I use the cache-type='none' with long transactions? What is causing a PersistenceException with long transactions and how do I fix it? OQL Is there any document available for Castor OQL? The OQL document describes several phases of development. Which is the current phase? Does Castor OQL support sub-queries? I cannot get Castor OQL to join two objects for me. Is it supported? Can I write a pass-thru OQL? Does Castor OQL support struct? How do I structure a query using the 'LIKE' expression? Does Castor support the SQL 'IN' expression? Features requests Can a foreign key be part of multiple primary keys? Is polymorphic collection supported? Data model issues Is it possible to map an object to more than one tables? Can an object with the same identity be re-created after being removed in the same transaction? What is a dependent object? Can a data object involved in many-to-many relationship be dependent? Castor JDO design How does Castor JDO work anyway? Does Castor support two-phase commits? How is this implemented? Does Castor support nested transaction? Working with open source databases Does Castor support PosgreSQL? Does Castor support MySQL? Which Open Source database is supported better? RDBMS-specific issues MySQL Use of DATETIME fields in general Use of TIMESTAMP fields & NULLs in long transactions MySQL 4.1.x and upgrade issues Oracle Oracle & (C|B)LOB fields Castor & Logging How can I integrate Castor's logging with a logging infrastructure using Log4J? Can I see what SQL statement Castor issues to the database as a result of an operation? How can I disable the use of JDBC proxy classes? Lazy Loading related questions How do I configure the JDO mapping to use the lazy loading feature for 1:1 relations? Lazy loading for 1:1 relations and serialization How do I configure the JDO mapping to use the lazy loading feature for 1:m and M:N relations? I have modified my mapping to use lazy loading. Now I get the error 'no method to set value for field: com.xyz.ClassB in class: ClassMolder com.xyz.ClassA' or 'org.exolab.castor.jdo.DataObjectAccessException: no method to set value for field: com.xyz.ClassB in class: ClassMolder com.xyz.ClassA'. What am I doing wrong? Tuning for LOBs Database-specific issues HSQL and identity key generators Changing database configurations ## Castor's relation to other specifications ### Does Castor JDO comply with the SUN JSR-000012 specification? No, Castor JDO doesn't comply with the SUN's JDO specification. Although Castor JDO carries very similar goals as SUN's JDO, it has been developed independently from the JSR. Although it is not impossible to shape (perhaps "hammer" is a more descriptive verb) Castor JDO into the SUN's JDO specification, there are several major technical differences which make it unfavorable to do so. Castor is RDBMS centric. Each persistence object loaded by Castor is locked. Locks in Castor are observable, meaning that locks may not be granted because of timeout or deadlock. On the other hand, the SUN's JDO hides details about locks. Internally, Castor JDO maintains a single copy of lock (and cache) for each active persistence object for all transaction. SUN's JDO specification implicitly requires a copy of cache per object per transaction. SUN's JDO also implicitly requires a bytecode modifier which Castor doesn't require. Castor also provides other features, such as key generators, long transaction support and OQL query which cannot be found in SUN's JSR. ### Is Castor JDO better than EJB CMP? The relation between JDO and EJB Container-Managed Persistence is more complicated than simply saying, "one is better than the other". An Entity Bean may manage persistence itself - the EJB specification calls this Bean Managed Persistence (BMP). Alternatively, the Entity Bean may rely on an EJB container to manage all peersistence automatically - the EJB specification calls this Container Managed Persistence (CMP). When implementing BMP, an Entity Bean may use Castor JDO as its persistence mechanism, or it may use others methods, such as dealing with JDBC directly. During CMP, an EJB Container vendor may implement their CMP on top of Castor JDO. In such an implementation, Castor JDO will be used to persist the Entity Bean. If a developer would like to take advantage of an EJB's life-cycle management, security, the "write once deploy anywhere" promise and other distributed business application facilities, then EJB will be the right choice. Otherwise, the fact that Castor is simple, is Open Source (you can always include Castor in your application or product), has much less overhead, provides more design freedom, and is integrated with Castor XML may be enough of a reason to choose Castor JDO. ## XML related questions ### Is it possible to make XML marshalling transactionally using Castor? No. The decision of putting XML and JDO together is NOT intended to make XML marshalling transactional. Instead, the integration is done to help developers of a typical client-server situation whereby an application server receives incoming XML messages, process the messages and replies to the client. With Castor, incoming XML messages can be unmarshaled into data objects. Required information can be obtained from a database using JDO in form of data objects. With this approach, all data manipulation can be done in an object-oriented way. Changes to JDO data objects can be committed transactionally, and result data objects can be marshaled into XML and returned to the client. ### Is it possible to do queries on a XML file using Castor? No, Castor does not provide an OQL query facility on a XML file. If querying is important for you, you should consider using a DBMS to store your data instead of using XML files, especially if querying performance is a concern. Another alternative is parse an XML Document directly and use XPath to retrieve Nodes and/or NodeSets from an XML Document. Other open source tools which provide this functionality are:
- | SAXPath
- | Jakarta Commons JXPath
## Technical questions ### Where can I find some examples to start with? Download the full SVN snapshot and look into the src/tests/jdo directory. ### I have encountered problems using Sun JDBC-ODBC bridge with Castor... It cannot be used with Castor, because it doesn't allow more than one open `ResultSet` at the same time. Either use JDBC driver of type > 1, or use some other JDBC-ODBC bridge without such a restriction (for example, from Easysoft). ### My get-method for the Collection of dependent objects returns null. Why? You should initialize the Collection yourself:
    private Collection _children = new ArrayList();

    public Collection getChildren() {
        return _children;
    }
### Should my JDO classes implement some special interface? In general, no. If you need some behavior that is not directly supported by Castor, you can implement interface `org.exolab.castor.jdo.Persistent`. In order to use dirty checking for long transaction you should implement interface `org.exolab.castor.jdo.TimeStampable`. If you need an example of use of these interfaces, see Persistent.java and TestPersistent.java among Castor JDO tests. ### Can Castor automatically create/remove related objects? First of all, let's agree upon terminology. We distinguish dependent and independent objects:
- | dependent objects are bounded to the parent object's lifecycle
- | independent objects have independent lifecycle
Thus, dependent objects are created/removed automatically, when their parent object is created/removed, while all operations on independent objects should be performed explicitly. However, with Castor 0.8.x you cannot describe explicitly the kind of object. Instead, the following rule applies: if you have one-to-many relation, and each side of the relation refers to another (Collection attribute on "one" side, simple attribute on "many" side), then "many" side is a dependent object. All other objects are independent. In particular, related objects via one-to-one relation are not created/removed automatically. With Castor 0.9 dependent objects should be described via "depends" attribute of "class" element in mapping configuration file. If you wish some independent object was created and/or removed automatically on operations on other independent object, you may use interface Persistent to code the desired behavior. ### Is Castor JDO using any connection pooling mechanism to improve the overall performance? No, Castor JDO doesn't have any built-in JDBC resource pooling. However the framework can transparently use any resource pooling facilities provided through DataSource implementation or -even better- through JDNI. In fact we even recommend people to use some Connection and PreparedStatement pool with Castor as this can increase Castor's performance 3-5 fold. For example the following set of statements:
    db.begin();
    db.execute(...)
    db.commit()
will be executed in much less time with the resource pooling because it will avoid creating a new physical JDBC connection at every execution. With Oracle, instead of specifying the usual JDBC driver you can use a DataSource that specifically provides some Connection caching/pooling. Thus if your jdo config file looks like :
            <database name="..." engine="oracle" >
                <driver class-name="oracle.jdbc.driver.OracleDriver"
                        URL="jdbc:oracle:thin:@localhost:1521:TEST" >
                    <param name="user" value="SYSTEM"/>
                    <param name="password" value="manager"/>
                </driver>
                ...
            </database>
then it can be changed into (for example):
            <database name="..." engine="oracle" >
                <data-source class-name="oracle.jdbc.pool.OracleConnectionCacheImpl">
                    <params URL="jdbc:oracle:thin:@localhost:1521:TEST"
                            user="scott"
                            password="tiger"
                    />
                </data-source>
                ...
            </database>
When Castor is used inside a Container such as an EJB container (within BMP or Session Bean), then the Container usually provides the JDBC resource through the JNDI ENC, which implicitely includes pooling facilities. ### I am getting ClassNotFoundException for my JDO class, but it is in the class path. Why? Probably castor.jar file is in jre/lib/ext directory. In this case you should call:
          jdo.setClassLoader(getClass().getClassLoader());
before jdo.getDatabase(). ### I am getting exception 'the class ... is not persistence capable...'. Why? In this case as well as in many others you can get more information with the help of logging. Call:
      jdo.setLogWriter(Logger.getSystemLogger());
and seek in the output for warnings and errors. ### I call db.remove() on the dependent object and commit, but this doesn't work... You should not add/remove dependent objects directly. In order to add/remove the dependent object you should just add/remove it from the collection in the master object and call db.commit() Dependent objects cannot be created/removed explicitly. It's created automatically when it is added to a master object, and removed automatically when it de-linked/dereferenced from a master object. Otherwise, we will be encounter into problem where a dependent object created explicitly but removed implicitly (delinked from a master object), or vice versa. It can also lead to other problems that are harder to detect. ### How should I represent string/date/boolean literals in OQL query? It is recommended to replace literals with parameters and to set them via `OQLQuery.bind()`, for example:
    OQLQuery query = db.getOQLQuery("SELECT p FROM Person p "
          +"WHERE name LIKE $1 AND dob>$2 AND married=$3");
    query.bind("John %");
    query.bind((new SimpleDateFormat("yyyy-MM-dd"))
           .parse("1960-01-01"));
    query.bind(false);
### I get 'java.lang.AbstractMethodError: getBigDecimal' for numeric fields. Why? Your JDBC driver is not JDBC 2.0 compliant, upgrade it or find another one. ### Does Castor support both one-way and two-way relationships? Typcially a relationship between two objects is either one-way (aka uni-directional) or two-way (aka bi-directional). Officially, Castor currently only supports bi-directional relationships. For example, if an `Order` object contains a reference to a `LineItem` object, the `LineItem` object must contain a reference to the Order object. However, this requirement is not enforced in all situations. This is a very complex problem to solve. So until Castor is expanded the support uni-directional relationships, the best policy is to implement the bi-directionalality for all relationships. This will ensure proper functionality. ### I have an object that holds a relation to itself. Does Castor support this? This is a very common occurrence in an object model and is known as a self-referenential relationship. Unfortunately, Castor does not currently support self-referential relationships. An example of such a relationship occurs when a `Folder` object contains a reference to another `Folder` object. Castor does not currently support this. However, there are ways around this limitation. One way is to manage this type of relationship manually. For example, let's say that a parent object `FolderA` needs to hold references to child objects `FolderB`, `FolderC` and `FolderD`. The `Folder` object contains not only a property to hold its own id, but also a property to hold its parent id (we'll call this `parentId`). The `parentId` property is used to determine if there is a relationship to another `Folder` object. If `parentId` is null, there is no relationship. If `parentId` is populated, there is a relationship and the object tree can be walked by comparing the object id to the `parentId`. When the two properties are equal, you're at the top of the tree. Another say to solve this problem is to make use of an intermediary object. For example, a `Folder` object contains a `Reference` object in lieu of the actual `Folder` object. The `Reference` object is somewhat of a proxy object whereby it only contains enough information to identify the object to which the `Reference` object refers. Then the `Folder` object can be easily instantiated via the information contained in the `Reference` object. ### Why do I get an ObjectModifiedException when trying to commit a transaction? The dirty checking engine will throw an `ObjectModifiedException` when the values in the cache and in the database are different. This can happen when someone else changed the database content, but also when type mapping is not reversible. For example, if a java timestamp (`java.util.Date`) is stored as a DATE, the time part is lost and the dirty checking will fail. Oracle cannot tell the difference between an empty String and a null value: if an attribute value is an empty String, dirty checking will also fail. Some precision loss sometimes occur with floating point numbers. To avoid this, always use reversible mapping conversions. If this is not possible, mark the fields with `dirty="ignore"` in the mapping file. ### I'm receiving a java.sql.SQLException: ORA-01461 When using Weblogic Portal 4.0 with Oracle I am receiving the following error:
    java.sql.SQLException: ORA-01461: can bind a LONG value only for insert into a LONG column
According to Weblogic Release Notes, this error can remedied by setting a Weblogic environment variable. ## Castor and performance caches ### Sometimes long transaction fails: on update() it is thrown ObjectModifiedException. Why? Most probably the object that is being updated has more than 100 related objects of one class and the cache size for this class is not enough. You should either increase the size of the cache or change the cache type to time-limited (the default cache type is count-limited, the default size is 100), for example:
    <class ...>
      <cache-type type="count-limited" capacity="1000"/>
      ...
    </class>
### Can I use the cache-type='none' with long transactions? As of release 0.9.5.3, you cannot. When using a cache of type 'none' with your 'Timestampable' objects, a MappingException is thrown when performing long transactions. Currently, Castor requires a (performance) cache of type other than 'none' to be used with classes that implement the 'TimeStampable' interface. In other words, if you want to use long transactions, please make sure that you use one of these cache types: 'unlimited', 'count-limited' or 'time-limited'. The next entry has some more information about a potential cause of confusion in the context of long transactions and a cache type other than 'unlimited'. ### What is causing a PersistenceException with long transactions and how do I fix it? With long transactions, sometimes update() throws a PersistenceException. As of release 0.9.5.3, Castor requires a (performance) cache (of type other than 'none') to be used with classes that implement the 'TimeStampable' interface. Please note that if you are using a cache type other than 'unlimited', it is possible that objects expire from the cache. This case will be highlighted to you by a PersistenceException being thrown. In this cases, please consider switching to cache type 'unlimited' (if possible) or increase the size of the cache according to your needs when using 'count-limited' (which has a default capacity of 100). ## OQL ### Is there any document available for Castor OQL? Yes. It is available from the Castor website: Advanced JDO --> OQL ### The OQL document describes several phases of development. Which is the current phase? We are currently working on Phase 3. ### Does Castor OQL support sub-queries? Not yet ### I cannot get Castor OQL to join two objects for me. Is it supported? Yes or no. Castor OQL supports implicit joins. And, in most case, you simply don't need explicit join. Consider the following example,
    SELECT o FROM Order o, LineItem i WHERE o.id = i.id AND i.price > 100
It is simply equivalent to the following OQL
    SELECT o FROM Order o WHERE o.lineItem.price > 100
### Can I write a pass-thru OQL? Yes. Just put "CALL SQL" keywords in front of your SQL statement. For example,
    OQLQuery oql = castorDb.getOQLQuery(
        "CALL SQL SELECT id, name, date "+
        "FROM user WHERE upper(name) like $1 AS myapp.Product");
But remember that the order of the fields listed must match what is defined in the mapping file. ### Does Castor OQL support struct? No, Castor OQL doesn't support struct. For example, the following query CANNOT be done:
    select c.name, c.age from Client c
### How do I structure a query using the 'LIKE' expression? A query using the 'LIKE' expression includes the use of the SQL wildcard '%'. The wildcard must be included in the
    bind()
statement:
            OQLQuery oql = castorDb.getOQLQuery( "SELECT p FROM Product p WHERE p.name LIKE $1" );
            oql.bind( "%widget%" );
### Does Castor support the SQL 'IN' expression? Yes. However, the full expression is a bit different using the LIST keyword. The following example provides a demonstration:
    SELECT p FROM Product p WHERE p.id IN LIST ( 123, 456, 789 )
If identifiers other than numbers are used, those identifiers must be quoted:
    SELECT p FROM Product p WHERE p.name IN LIST ( "abc", "jkl", "xyz" )
To include NULL values in the 'IN' list, use the 'nil' keyword:
    SELECT p FROM Product p WHERE p.name IN LIST( "ABC", nil )
It is even possible to include bind values in the 'IN' lists using the following syntax:
    SELECT p FROM Product p WHERE p.id IN LIST( $(int)1, $2, $3 )
## Features requests ### Can a foreign key be part of multiple primary keys? Unfortunately, the answer is no. We're aware that many users need this feature so it is a very high priority in our todo list. If foreign key is the primary key, as a workaround you may consider using the 'extends' relationship. ### Is polymorphic collection supported? Unfortunately, the answer is no. In version 0.8.11, we tried to enable polymorphic collection by introducing the notation of Object Reloading. Object Reloading delegates the determination of the class to a data object. However, it is proved that reloading can only be done before any instance of the target object is returned to user, and we have no way to determine that. As a result, we removed the support in version 0.9.x. In the near future, we are going to use a new mechanism to provide extends. The new mechanism loads a table with an SQL statement that outer-joins all of the extending tables with the base. The existence of an extended table row can be used to determine the class of a data object. Notice that all extended table rows of the same entity should always be stored in the same data-store. In the further future, we also want to let users to define a discriminator column (or determinance field). Basing on the value of discriminator columns in the base table, the bridge layer fetches the additional information and returns the combined entity with the appropriate list of entity classes. ## Data model issues ### Is it possible to map an object to more than one tables? Yes, if the two tables share the same identity, you can specify one data object to "extends" the other. When the extended data object is loaded, its table (specified in <map-to/> will be joined with all the tables of its super classes'. Another solution (in my opinion more flexible) is having two set of methods in the main object. One for Castor JDO and another for application. Consider the following example:
    class Employee {
       private int _employeeNumber;
       private Address _address;
       private Collection _workGroup;

       public int getEmployeeNumber() {
            return _employeeNumber;
       }
       public void setEmployeeNumber( int id ) {
            _employeeNumber = id;
       }

       // methods for Castor JDO
       public Address getAddress() {
           return _address;
       }
       public void setAddress( Address address ) {
            _address = address;
       }
       public Collection getWorkGroup() {
            return _workGroup;
       }
       public Collection setWorkGroup( Collection workGroup ) {
            _workGroup = workGroup;
       }

       // methods for application
       public String getAddressCity() {
           return _address.getCity();
       }
       public String getAddressZip() {
           return _address.getZip();
       }
       // ...
    }
### Can an object with the same identity be re-created after being removed in the same transaction? Yes, as long as the deleted object is the same instance as the one being recreated. ### What is a dependent object? Dependent object is actually a concept from the object-oriented database world. A dependent object's lifetime depends on its master object. So, create/delete/update of the master object will trigger the proper actions, newly linked dependent object will be automatically created and de-referenced dependent object will be removed. The concept was also used in the earlier CMP 2.0 draft, although it is later removed. ### Can a data object involved in many-to-many relationship be dependent? No ## Castor JDO design ### How does Castor JDO work anyway? Let's use object loading as an example. When an application invoke db.load, the underneath `TransactionContext` is invoked. If the object with the requested identity exists in the `TransactionContext`, previously loaded object in the `TransactionContext` is returned. Otherwise, `TransactionContext` creates a new instance of the interested type and invokes LockEngine to "fill" the object. `LockEngine` acquires a lock of the object, and it makes sure `ClassMolder` has a thread-safe environment when it invokes `ClassMolder`. In `ClassMolder`, if the interested set of fields representing the object is not existed in the cache yet, `SQLEngine` will be invoked and the set of fields from the underneath data store will be returned. `ClassMolder` binds the loaded or cached fields into the new instance. `ClassMolder` requests the `TransactionContext` to load the related and the dependent objects. Eventually, the object is returned after all of the relationships are resolved. The process of commit has several states. The first state is preStore. In preStore state, objects existing in the `TransactionContext` are checked for modification one by one, including dependent and related objects. De-referenced dependent objects are marked as delete-able, and reachable dependent objects are added into `TransactionContext`. An object is marked "dirty" if it is modified. Also, if any modification should cause any related or dependent to be dirty, the related or dependent object is marked as dirty as well. After the preStore state, all dirty object is properly stored. And, all marked delete object will be removed. Then, the connection is committed. If succeed, all cache with be updated. Finally, all lock is released. ### Does Castor support two-phase commits? How is this implemented? Yes, via `javax.transaction.Synchronization` interface. For Castor to work with global transactions, Castor must be configured to use global transaction demarcation in its main configuration file:
    <jdo-conf>
       ...
       <transaction-demarcation mode="global" >
          <transaction-manager name="jndi" />
       </transaction-demarcation>
    </jdo-conf>
When retrieving a Database instance via
    ...
    JDOManager.loadConfiguration("jdo-conf.xml");
    JDOManager jdo = JDOManager.createInstance("mydb");
    ...
    Database db = jdo.getDatabase();
the `Database` implementation will authomatically be registered with the transaction manager, as it implements `javax.jta.Synchronization` interface. Subsequently, the transaction manager communicates with Castor via the beforeCompletion() and afterCompletion() calls. ### Does Castor support nested transaction? No ## Working with open source databases ### Does Castor support PosgreSQL? Yes, starting from PostgreSQL 7.1, where outer joins support has been added. ### Does Castor support MySQL? Yes, starting from MySQL version 3.23, where transaction support has been added. Note: if you use Mark Matthews MySQL JDBC driver, then you need version 2.0.3 or higher. ### Which Open Source database is supported better? For now only with PostgreSQL 7.1 and SAP DB you get a full set of Castor features. Other Open Source databases don't support select with write lock, so db-locked locking mode doesn't work properly (it works in the same way as exclusive locking mode). All other Castor features are supported with MySQL, Interbase, InstantDB and Hypersonic SQL. ## RDBMS-specific issues ### MySQL #### Use of DATETIME fields in general MySQL in it's current releases (4.0.x and 4.1.x) does not store fractions of a second in fields of type DATETIME that are mapped to java.sql.TimeStamp fields. As a result, Castor will throw ObjectModifiedExceptions during commits as Castor internally maintains fractions of a seconds. Instead, Please use a column type that can be mapped to a long value, as Castor internally handles conversion between java.util.Date and long values with the required precision. #### Use of TIMESTAMP fields & NULLs in long transactions In MySQL, fields of type 'Timestamp' exhibit special behaviour wih regards to NULLs. When inserting a "NULL" into such a field, it actually inserts the current date and time. This causes problems for Castor's caching mechanism since Castor internally believes the field is still NULL. If you subsequently perform an update on the entry whilst it is still in the cache, an ObjectModifiedException will be thrown, because Castor believes that the database record has changed in the meantime. The workaround is to use a DATETIME field instead of TIMESTAMP. #### MySQL 4.1.x and upgrade issues As with many other open source products, MySQL seems to be changing slightly from version to version. There seems to be a problem with concurrency in MySQL 4.1.5 that can be resolved by upgrading to 4.1.7 or higher. At Castor we frequently use Connector/J 3.0.16, 3.1.13 and nowadays 5.1.6 to execute our test farmework. If you use one of this versions of Connector/J you should be on the safe side. If you are hit by any problems using one of these versions, please let us know. ### Oracle #### Oracle & (C|B)LOB fields As of Oracle release 10g, the problem of Castor to handle BLOBs with a size greater than 2kB and CLOBs with a size greater than 4 kB correctly has been resolved. With the 10 release of Oracle's JDBC driver, both driver types (type 2 and type 4) can be used. With earlier releases, only the OCI driver (type 2) seems to work. The 10g release of the Oracle JDBC Driver can be downloaded here. ## Castor & Logging ### How can I integrate Castor's logging with a logging infrastructure using Log4J? Please see this message from the mailing list. It includes an adapter class that will provide this functionality. (Thanks John!) ### Can I see what SQL statement Castor issues to the database as a result of an operation? Yes, you can. By default, Castor uses JDBC proxy classes (wrapping `java.sql.Connection` and `java.sql.PreparedStatement`) that capture the core SQL statements as generated by Castor and the user-supplied parameters at execution time of the various persistence operations, and outputs them to the standard logger used by Castor. By default, these output statements are not visible, as the log level is set to level 'info'. To see these SQL statements, please increase the log level to level 'debug' in `log4j.xml`. ### How can I disable the use of JDBC proxy classes? As of release 0.9.7, a new property
    org.exolab.castor.persist.useProxies
has been added to `castor.properties` to allow configuration of the JDBC proxy classes mentioned above. If enabled, JDBC proxy classes will be used for logging SQL statements. When turned off, no logging statements will be generated at all. ## Lazy Loading related questions ### How do I configure the JDO mapping to use the lazy loading feature for 1:1 relations? Let us convert one of the classes from the JDO examples to use lazy-loading. In the example model, every Product belongs to one ProductGroup. This is reflected in the conventional mapping as below. Here's the mapping for Product:

    <!--  Mapping for Product  -->
    <class name="myapp.Product"
           identity="id">
       <description>Product definition</description>
       <map-to table="prod" xml="product" />
       <field name="id" type="integer">
           <sql name="id" type="integer" />
           <xml name="id" node="attribute"/>
       </field>

       <!-- more fields ... -->

        <!--  Product has reference to ProductGroup,
              many products may reference same group  -->
        <field name="group" type="myapp.ProductGroup">
          <sql name="group_id" />
          <bind-xml name="group" node="element" />
        </field>

    </class>
Let us now make the relationship between Product and ProductGroup use lazy loading. The relevant field in Product can be re-written like so:

        <field name="group" type="myapp.ProductGroup" lazy="true">
          <sql name="group_id" />
          <bind-xml name="group" node="element" />
        </field>
There have been one change only. We have placed the attribute lazy="true" in the field element. Note that no change is required in the ProductDetail mapping. ### Lazy loading for 1:1 relations and serialization Please note that Castor does not support full serialization of lazy-loaded objects at this time. Rather than serializing just the information required to re-build the underlying proxy implementation during deserialization, Castor will materialize (read: load from the persistence store) all objects before serialization. As this can lead to a lot of database accesses, please use this feature carefully. A full working solution will be provided with the next release. ### How do I configure the JDO mapping to use the lazy loading feature for 1:m and M:N relations? Let us convert one of the classes from the JDO examples to use lazy-loading. In the example model, one Product can contain many ProductDetails. This is reflected in the conventional mapping as below. First, the mapping for Product:
    <!--  Mapping for Product  -->
    <class name="myapp.Product"
           identity="id">
       <description>Product definition</description>
       <map-to table="prod" xml="product" />
       <field name="id" type="integer">
           <sql name="id" type="integer" />
           <xml name="id" node="attribute"/>
       </field>

       <!-- more fields ... -->

       <!-- Product has reference to ProductDetail
                many details per product  -->
       <field name="details" type="myapp.ProductDetail" required="true"
               collection="vector">
           <sql many-key="prod_id"/>
           <xml name="detail" node="element" />
       </field>
    </class>
Now let us examine ProductDetail. Note, the relationship is mapped bi-directionally as must be all relationships when using Castor JDO.
    <!--  Mapping for Product Detail -->
    <class name="myapp.ProductDetail" identity="id" depends="myapp.Product" >
       <description>Product detail</description>
        <map-to table="prod_detail" xml="detail" />
       <field name="id" type="integer">
           <sql name="id" type="integer"/>
           <xml node="attribute"/>
        </field>
        <field name="product" type="myapp.Product">
           <sql name="prod_id" />
           <xml name="product" node="element" />
        </field>

           <!-- more fields ... -->

    </class>
Let us now make the relationship between Product and ProductDetail use lazy loading. We need only change the way that the relationship to ProductDetail is specified in the mapping of Product. The relevant field in Product can be re-written like so:
    <field name="details" type="myapp.ProductDetail" required="true" lazy="true"
                collection="collection">
       <sql many-key="prod_id"/>
       <xml name="detail" node="element" />
    </field>
There have been two changes.
- | We have placed the attribute lazy="true" in the field element
- | We have changed the type of the underlying collection type to be a `java.util.Collection` by changing the field element attribute to collection="collection".
Note that no change is required in the ProductDetail mapping. ### I have modified my mapping to use lazy loading. Now I get the error 'no method to set value for field: com.xyz.ClassB in class: ClassMolder com.xyz.ClassA' or 'org.exolab.castor.jdo.DataObjectAccessException: no method to set value for field: com.xyz.ClassB in class: ClassMolder com.xyz.ClassA'. What am I doing wrong? To use lazy loading you must also change the persistent class that will hold the related objects. At the very highest level, you need to provide a set method that accepts a java.util.Collection for the field in question. This is demonstrated by changing the JDO examples below. In the original Product class we have the following code:
    import java.util.Vector;
    ...
    private Vector       _details = new Vector();
    ...
    public Vector getDetails()
    {
       return _details;
    }

    public void addDetail( ProductDetail detail )
    {
       _details.add( detail );
       detail.setProduct( this );
    }
Let us now make the necessary changes to set up lazy loading. As stated above we now require a special set method for the related ProductDetails (stored originally as a `java.util.Vector`) that accepts a `java.util.Collection` as an argument. This mandates that we must also use a `java.util.Collection` to hold our ProductDetails. If this is not added, you will receive the errors above.
    import java.util.Collection;
    ...
    private Collection       _details;
    ...
    public Collection getDetails()
    {
       return _details;
    }

    public void setDetails( Collection details )
    {
       _details = details;
    }
## Tuning for LOBs Castor JDO provides a property in `castor.properties` for adjusting the size of the JDBC driver's buffer for reading LOBs (BLOBs and CLOBs) from the database. The propery is named `org.exolab.castor.jdo.lobBufferSize` and its default is 5120 bytes (5k). The size of this buffer can be tuned for larger LOBs, but is dependent upon the JDBC driver implementation being used and what it supports. ## Database-specific issues ### HSQL and identity key generators Due to a product limitation, AUTO_INCREMENT sequences in HSQL begin with 0 rather 1, as is the case with most other RDBMS. As a result of this, long transactions will not work for the object with the identity 0, and a ObjectModifiedException will be thrown. To avoid this issue, we recommend inserting a temp object into the database in question, and removing thereafter so that no object with identity 0 is stored. ## Changing database configurations Some applications need to change the database connection or switch between different mapping files on the fly. Because Castor caches database configurations per name, you would have to register a new JDO configuration using a distinct name for any of the different configurations. Instead you can call clear() to reset the database registry before registering the new configuration as follows:
    // Reset database registry
    org.exolab.castor.jdo.engine.DatabaseRegistry.clear();
| 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. |