Packages: org.aris.OODB org.aris.hldb org.aris.cache.UniversalCache
Documentation : Javadoc
Package org.aris.OODB: OODB Framework: Object Oriented
access to DataBases
Version : 1.0Beta-B
Author : Konstantine Kougios
Known bugs :
None so far.
Extensive beta testing
hasn’t been done in the library, though there is a test where 100 threads are
using the library without problems.
Modifications:
# Version Description
1. 1.0Beta-A Now it works with jdom version 1.0.
2. 1.0Beta-B Ant support has been added. Lib directory now contains all needed jars.
Downloads
OODB (including org.aris.hldb and
org.aris.cache). See the classpath section for jars that are needed to
run/use OODB. Jars are contained in the zip file.
Purpose
OODB purpose is to read a database and convert it’s structure into java classes and optionally other text formats. Java classes are able to perform select, insert and update operations. Templates are used to convert databases to java or text formats. Templates are xsl files.
Database : table1,table2,table3 è OODB + template(s) è Java: table1.java, table2.java, table3.java.
Also:
Database : table1,table2,table3 è OODB è text files: table1, table2, table3 or 1 single text file for the whole database.
The package contains a real-life template for use with database projects which provides caching or rows, insertions, updates and deletes and navigation via relationships of the database. Custom templates can be created too to satisfy database project needs.
Before using, a good knowledge of xml, xslt, databases and java is necessary.
Quick intro
OODB currently works with SQL server 2000 database. Let’s see some code produced by OODB, for the Northwind database sample provided by Microsoft. Here is the database schema:
Schema 1: Microsoft’s Northwind database example
Lets see some of the methods/fields of the Employees class (Employees.java) produced by OODB:
…
protected int EmployeeID;
protected String LastName;
protected String FirstName;
protected String Title;
protected String TitleOfCourtesy;
protected java.sql.Date BirthDate;
protected java.sql.Date HireDate;
protected String Address;
protected String City;
protected String Region;
…
…
public int getEmployeeID();
protected void setEmployeeID(int value); // autoincrement primary key can’t be set.
public String getFirstName();
void setFirstName(String value);
…
public synchronized void insert() throws SQLException;
public int update() throws SQLException;
public static int delete() throws SQLException;
…
…
Various other utility functions are created by the templates, like toString() method for easy debugging, toXML(int depth) version to convert a row (and down to depth related tables) in XML, etc.
Example: Navigating the Northwind database using the java classes generated with OODB framework.
This example (which is included in the download package), is navigating the Northwind database, using the classes generated by OODB. Every class has the same name as the table it refers to, appending an “Cached” in the end, i.e. “EmployeesCached”, “CategoryCached” etc. (Class name extension is optional and it is used because OODB can produce sets of classes for a database, that extend one an other, in this example actually the ‘TABLE’Cached classes extends the ‘TABLE’Base classes and add memory caching of rows).
Here is the example. It would be much easier to understand it if you had the database scheme of Northwind while checking the code. The example first retrieves some records from the database in order for you to generally see how tables are mapped to classes. Then it does something more complex: for every employee which lives in “London”, it gets any available information from the database, i.e. what orders they have, from which customer etc.
Legend:
CS : the template uses a package named org.aris.hldb, which provides easy and fast programmatically access to databases using stored procedures. It is included in the download package. Don’t get bothered by this at this moment. See it as a Connection to the database object.
globals.Cache: a class which stores the instance of org.aris.UniversalCache. This is the memory cache used for caching table rows. It is included in the download package. Again, don’t be bothered by this one at this moment.
Example 1: Usage of classes produced by OODB
// csNorthwind is already pointing to Northwind database
public void NavigateNorthwind(CS csNorthwind,boolean dump) throws SQLException, CloneNotSupportedException
{
// if we know the primary key(s), we can just get the object by it.
// This will get the territory with id 02903. It will first lookup the cache and if not found,
// it will query the database “Territories” table . Since this is the first time we lookup this territory, the
// lookup will be done to the database.
TerritoriesCached ter=TerritoriesCached.instance(csNorthwind,"02903");
// now we'll do an update to the Region table. First we'll get the region
// that this territory points to and save it so that we can restore the
// database state later. Then , we'll point this territory to regionId 4.
// We'll update the database and do some debugging dump of the cache.
// Finally, we'll restore the territory.regionId to it's previous value,
// in order to keep our database as it were.
// get the old regiod id
int oldId=ter.getRegionID();
// get the region of this territory and dump it just to see
// what is stored. Note: all classes implement the toString()
// method, and you can see what they contain during debugging.
RegionCached reg=ter.getRegionIDRef();
if (dump) reg.dump("regionCached==>");
// now we'll change the region of this territory. We could do it in
// 2 ways, by providing the ID of the new region, or by providing an
// RegionCached object. We'll just provide the ID here.
ter.setRegionID(4);
ter.update();
// .. and the same by providing the RegionCached object:
// ter.setRegionIDRef(RegionCached.instance(csNorthwind,4));
// ter.update();
// for debugging we'll dump all contents of the cache to the console
if (dump) Cache.getCache().dump(true);
// restore the database to it's previous state.
ter.setRegionID(oldId);
ter.update();
// dump the cache again to see if it is updated
if (dump) Cache.getCache().dump(true);
if (dump) System.out.println("\n\n\n\n");
// find up to 100 employees who live in London
// Note: getResultSetWith... should be used if the result count could be high.
Iterator it=EmployeesCached.getIteratorWithCityValueOf(csNorthwind,"London",100);
while (it.hasNext()) // iterate through all employees living in London
{
// get the employee
EmployeesCached emp=(EmployeesCached)it.next();
// get some info about him
String emp_firstName=emp.getFirstName();
java.sql.Date emp_HireDate=emp.getHireDate();
// and go on ...
// find to whom does this employee report to
EmployeesCached reports=emp.getReportsToRef();
//get some info about the "boss"
String boss_city=reports.getCity();
String boss_firstName=reports.getFirstName();
// and do smthing with them ...
// ...
// on to the next tables.
// get all the Orders for this employee
Iterator oit=OrdersCached.getIteratorWithEmployeeIDValueOf(csNorthwind,new Integer(emp.getEmployeeID()),Integer.MAX_VALUE);
while (oit.hasNext())
{
OrdersCached ord=(OrdersCached)oit.next();
// now get the customer who placed this order.
CustomersCached cust=ord.getCustomerIDRef();
// play with some fields.
String city=cust.getCity();
String address=cust.getAddress();
// and we don't do anything with them here ... it is just an example
// Do an update (commented out in order not to alter the Northwind database)
//cust.setCity("---C:Modified by OODB ---");
//cust.setAddress("---A:Modified by OODB ---");
//cust.update(); //this updates only fields. If the primary keys need to be updated too, call updateAll()
// now find the order details
Iterator odit=Order_DetailsCached.getIteratorWithOrderIDValueOf(csNorthwind,ord.getOrderID(),Integer.MAX_VALUE);
while (odit.hasNext())
{
Order_DetailsCached od=(Order_DetailsCached)odit.next();
// get the products for this order_details
ProductsCached prod=od.getProductIDRef();
// and get the suppliers of this products
SuppliersCached sup=prod.getSupplierIDRef();
String sup_city=sup.getCity(); // the city of the supplier
String sup_addr=sup.getAddress(); // the address
String sup_Company=sup.getCompanyName(); // and the name of the supplier's company
// ... do smthing with these values...
// ... go on with the product's categories.
CategoriesCached categ=prod.getCategoryIDRef();
String categ_name=categ.getCategoryName();
// note: you can't get images (and the rest of the BLOBS/CLOBS). You have to provide your own
// code to access those. But when inserting with insert(), or updating a table with images,
// the handle to the image must be provided.
// i.e. categ.setPicture(stream,length);
// A better way is to have blobs in seperate tables and access those with custom code.
}
}
}
Using OODB
ClassPath
org.aris.jar should be in your classpath, along with mssql server driver jars (get them from microsoft’s site). Also you need jdom.jar version 1.0, for xml parsing and saxpath.jar. If OODB throws an exception because it can’t find an xml parser, you will need to set the org.xml.sax.driver property (with jdom 1.0 it works fine).
Templates
Xslt templates and transformation is used to convert databases to java classes. Included in the download package, are 5 templates, 2 which are for demonstration reasons and use standard sql to execute the queries (simpleDBClass.xsl, simpleDBExt.xsl). The other 3 can be used to do some real life work!
All templates are in org.aris.oodb.templates package. More templates ofcourse can be added there.
Converting a database
To convert a database, first you need to make an xml configuration file, which defines what and how will the database be converted and what will be produced from it.
Configuration of OODB to convert a database
The configuration is an .xml file. Here is an example of converting the database using the simpleDBClass.xsl template. Only this template will be used, and only 1 class per table will be produced.
Example 2: A simple configuration for converting Northwind to java classes
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<oodb>
<database>
<!-- define the connection to the database -->
<connection>
<driver>com.microsoft.jdbc.sqlserver.SQLServerDriver</driver>
<string>jdbc:microsoft:sqlserver://localhost:1433</string>
<user>PUT_YOUR_NORTHWIND_DB_USERNAME</user>
<password>*******</password>
</connection>
<!—Debugging info will be printed by OODB while converting. Useful when creating custom templates-->
<debug>1</debug>
<!-- The catalog (database) that will be converted to classes -->
<catalog>Northwind</catalog>
<!-- templates to use for the conversion, along with subclassing templates and interfaces.
Note that file tag is necessary, while the rest are passed as is to the template,
so you can pass any parameters to your templates here!
-->
<templates>
<template>
<!-- this produces code with debugging output (simpleDBClass.xsl read’s them!) -->
<debug>1</debug>
<!-- template to use (it reads them from org.aris.oodb.templates package) -->
<file> simpleDBClass.xsl</file>
<!—convert both tables and views-->
<convertType>TABLE</convertType>
<convertType>VIEW</convertType>
<!-- each class will belong to this package, so make sure you have the directory created before running the conversion! -->
<package>test.db</package>
<!-- the output directory for the produced classes. -->
<outputDir>C:/Work/Java/OODBFrameworkTest/test/db/</outputDir>
<!-- additional imports for produced class files -->
<imports>
// --- a holder for custom imports ---
</imports>
<!-- class modifier (public , static or nothing) -->
<modifiers>public</modifiers>
<!-- extension to the class name, i.e. Employees + ext, EmployeesExample in this case -->
<ext>Example</ext>
<!—extends, we won’t extend any class for this example-->
<extends></extends>
</template>
</templates>
</database>
</oodb>
Ok, now when you run the oodb framework giving as parameter the filename of this xml, it will scan the database and write 1 class for each table in C:/Work/Java/OODBFrameworkTest/test/db/. The template we used is for demonstration only, i.e. it will fail in an insert if a string contains a quote character. But you can examine the code to take an idea of how things work.
A more useful example converts the Northwind database to 2 sets of classes, set “Base” and set “Cached” (the one we used in example 1). The Base is querying the DB with stored procedures and the org.aris.hldb package. The Cached is the only set of classes which is public and can be accessed while programming. It provides the row-caching layer.
This example produces the set of classes used in our example 1. Also it produces a .sql file which contains queries. Org.aris.hldb converts those .sql files to stored procedures. Check hldb docs for more information.
Files produced:
C:/Work/Java/OODBFrameworkTest/test/db/{$tableName}Base.java using the hldbBase.xsl, 1 file per table
C:/Work/Java/OODBFrameworkTest/test/db/{$tableName}Cached.java using the hldbCached.xsl, 1 file per table
C:/Work/Java/OODBFrameworkTest/test/db/queryNorthwind.sql single file for whole Northwind DB: query file used by hldb.
Example 3: produce real-life usage classes for the Northwind database
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<oodb>
<!--
================================================================================================
Convert the Northwind database.
2 sets of classes will be produced. Those which end with "Base" i.e. CategoriesBase and those
which ends with "Cached". The "Base" classes are protected. The Cached classes will be used
to query the database. These provide memory caching for the Base classes.
================================================================================================
-->
<database>
<!-- define the connection to the database -->
<connection>
<driver>com.microsoft.jdbc.sqlserver.SQLServerDriver</driver>
<string>jdbc:microsoft:sqlserver://localhost:1433</string>
<user>USERNAME</user>
<password>******</password>
</connection>
<!-- define how much debug info the conversion will output, valid values (0,1,2) -->
<debug>0</debug>
<!-- The catalog (database) that will be converted to classes -->
<catalog>Northwind</catalog>
<!--
Templates to use for the conversion, along with subclassing and interfaces.
Note that file tag is necessary, while the rest are passed as is to the template,
so you can pass any parameters to your templates here!
-->
<templates>
<!-- pass these custom params to all templates -->
<commonParams>
<!--nothing for this example -->
</commonParams>
<!-- With hldbBase.xsl template, we produce the Base classes for the tables -->
<template>
<!-- this produces code with debugging output -->
<debug>1</debug>
<!-- template to use -->
<file>hldbBase.xsl</file>
<willBeExtended>true</willBeExtended>
<!-- convert type of: (TABLE,VIEW] -->
<convertType>TABLE</convertType>
<convertType>VIEW</convertType>
<!-- each class will belong to this package -->
<package>test.db</package>
<!-- the output directory for the produced classes -->
<outputDir>C:/Work/Java/OODBFrameworkTest/test/db/</outputDir>
<!-- additional imports for produced class files -->
<!-- every produced class will use these imports (or whatever text is here will be pasted after package ... -->
<imports>
// --- a holder for custom imports ---
</imports>
<!-- class modifier (public , static or nothing) -->
<modifiers></modifiers> <!-- the Base classes will be protected -->
<!-- extension to the class name -->
<ext>Base</ext>
<!-- extends -->
<extends></extends> <!-- these classes won't extend anything -->
</template>
<!--
We produce classes for the tables, using a hldbCached.xsl template
These classes extends the ##Base classes, and provide memory caching of database records.
-->
<template>
<!-- this produces code with debugging output -->
<debug>1</debug>
<!-- template to use -->
<file>hldbCached.xsl</file>
<!-- convert type of: (TABLE,VIEW] -->
<convertType>TABLE</convertType>
<convertType>VIEW</convertType>
<!-- each class will belong to this package -->
<package>test.db</package>
<!-- the output directory for the produced classes -->
<outputDir>C:/Work/Java/OODBFrameworkTest/test/db/</outputDir>
<!-- additional imports for produced class files -->
<!-- every produced class will use these imports (or whatever text is here will be pasted after package ... -->
<imports>
// --- a holder for custom imports ---
</imports>
<!-- class modifier (public , static or nothing) -->
<modifiers>public</modifiers>
<!-- extension to the class name -->
<ext>Cached</ext> <!-- these classes names ends with "Cached" -->
<!-- extends -->
<extends>##Base</extends> <!-- the template we are using here, requires the classes produced by hldbBase.xsl -->
</template>
<!--
Common file output for all tables template. In this case, we create the query text file, which
isd parsed by hldb to create the stored procedures. The only difference here is that instead
of a <file> tag, we have an <outputFile> tag, which points to a file instead of a directory.
All table info is parsed by the hldbQuery.xsl template, to produce this outputFile.
-->
<template>
<!-- this produces code with debugging output -->
<debug>1</debug>
<!-- template to use -->
<file>hldbQuery.xsl</file>
<!-- convert type of: (TABLE,VIEW] -->
<convertType>TABLE</convertType>
<convertType>VIEW</convertType>
<!-- the output FILE -->
<outputFile>C:/Work/Java/OODBFrameworkTest/test/db/queryNorthwind.sql</outputFile>
<ext>Base</ext>
</template>
</templates>
</database>
</oodb>
Advanced topic: Creating custom templates
To create a custom xslt template, you need to know what xml does the OODB pass to your template. A way to find out is to give the database/debug of your xml config a value of 1. This dumps all xml passed to xsl, to the console.
Templates are stored in the org.aris.oodb.templates package. Examine the simpleDBClass.xsl to see how you can convert tables to java.
Here is an example of an xml passed to the xsl’s during the conversion of the Northwind. Your root is the <ROOT> node and you give xpaths in the form of /template/debug or /CLASSINFO/@tableName. As you can see, the <template> node is passed as is from your config file to the transformer. The table converted here is the “Categories” table.
Example 4: XML used during transformation of tables to classes
<ROOT>
<template>
<!-- this produces code with debugging output -->
<debug>1</debug>
<!-- template to use -->
<file>hldbBase.xsl</file>
<willBeExtended>true</willBeExtended>
<!-- convert type of: (TABLE,VIEW] -->
<convertType>TABLE</convertType>
<convertType>VIEW</convertType>
<!--
-->
<!-- each class will belong to this package -->
<package>test.db</package>
<!-- the output directory for the produced classes -->
<outputDir>C:/Work/Java/OODBFrameworkTest/test/db/</outputDir>
<!-- additional imports for produced class files -->
<!-- every produced class will use these imports (or whatever text is here will be pasted after package ... -->
<imports>// --- a holder for custom imports ---</imports>
<!-- class modifier (public , static or nothing) -->
<modifiers />
<!-- the Base classes will be protected -->
<!-- extension to the class name -->
<ext>Base</ext>
<!-- extends -->
<extends />
<!-- these classes won't extend anything -->
</template>
<commonParams>
<specialQueryCode>
</specialQueryCode>
</commonParams>
<CLASSINFO tableName="Categories" package="test.db" />
<CLASSNAME>CategoriesBase</CLASSNAME>
<COLUMN name="CategoryID" primaryKey="PK_Categories" primaryKeySeq="1" identity="1" javaType="int" asObject="Integer" dbType="int" dbTypeDef="int" dbSize="10" allocateVar="0" resultSetGetSet="Int" crossRef="0" order="1" nullable="0" toXmlMode="0" convertorToPrimitive="" java.sql.Types="java.sql.Types.INTEGER" remarks="No remarks for this field in the database (or the database driver doesn't return column remarks)." hasMore="1" />
<COLUMN name="CategoryName" primaryKey="" identity="0" javaType="String" asObject="" dbType="nvarchar" dbTypeDef="nvarchar(15)" dbSize="15" allocateVar="0" resultSetGetSet="String" crossRef="0" order="2" nullable="0" toXmlMode="1" convertorToPrimitive="" java.sql.Types="java.sql.Types.VARCHAR" remarks="No remarks for this field in the database (or the database driver doesn't return column remarks)." hasMore="1" />
<COLUMN name="Description" primaryKey="" identity="0" javaType="String" asObject="" dbType="ntext" dbTypeDef="ntext" dbSize="1073741823" allocateVar="0" resultSetGetSet="String" crossRef="0" order="3" nullable="1" toXmlMode="1" convertorToPrimitive="" java.sql.Types="java.sql.Types.LONGVARCHAR" remarks="No remarks for this field in the database (or the database driver doesn't return column remarks)." hasMore="1" />
<COLUMN name="Picture" primaryKey="" identity="0" javaType="java.io.InputStream" asObject="" dbType="image" dbTypeDef="image" dbSize="2147483647" allocateVar="0" resultSetGetSet="BinaryStream" crossRef="0" order="4" nullable="1" toXmlMode="2" convertorToPrimitive="" java.sql.Types="java.sql.Types.BLOB" remarks="No remarks for this field in the database (or the database driver doesn't return column remarks)." hasMore="0" />
<PRIMARYKEYS commaSep="CategoryID" commaSepJavaType="int CategoryID">
<KEY column="CategoryID" pkName="PK_Categories" keySeq="1" hasMore="0">
<COLUMN name="CategoryID" primaryKey="PK_Categories" primaryKeySeq="1" identity="1" javaType="int" asObject="Integer" dbType="int" dbTypeDef="int" dbSize="10" allocateVar="0" resultSetGetSet="Int" crossRef="0" order="1" nullable="0" toXmlMode="0" convertorToPrimitive="" java.sql.Types="java.sql.Types.INTEGER" remarks="No remarks for this field in the database (or the database driver doesn't return column remarks)." />
</KEY>
</PRIMARYKEYS>
<CROSSREFERENCES />
</ROOT>
Example 5: XML for table CustomerCustomerDemo
<ROOT>
<template>
<!-- this produces code with debugging output -->
<debug>1</debug>
<!-- template to use -->
<file>hldbBase.xsl</file>
<willBeExtended>true</willBeExtended>
<!-- convert type of: (TABLE,VIEW] -->
<convertType>TABLE</convertType>
<convertType>VIEW</convertType>
<!--
-->
<!-- each class will belong to this package -->
<package>test.db</package>
<!-- the output directory for the produced classes -->
<outputDir>C:/Work/Java/OODBFrameworkTest/test/db/</outputDir>
<!-- additional imports for produced class files -->
<!-- every produced class will use these imports (or whatever text is here will be pasted after package ... -->
<imports>// --- a holder for custom imports ---</imports>
<!-- class modifier (public , static or nothing) -->
<modifiers />
<!-- the Base classes will be protected -->
<!-- extension to the class name -->
<ext>Base</ext>
<!-- extends -->
<extends />
<!-- these classes won't extend anything -->
</template>
<commonParams>
<specialQueryCode>
</specialQueryCode>
</commonParams>
<CLASSINFO tableName="CustomerCustomerDemo" package="test.db" />
<CLASSNAME>CustomerCustomerDemoBase</CLASSNAME>
<COLUMN name="CustomerID" primaryKey="PK_CustomerCustomerDemo" primaryKeySeq="1" identity="0" javaType="String" asObject="" dbType="nchar" dbTypeDef="nchar(5)" dbSize="5" allocateVar="0" resultSetGetSet="String" FK_table="Customers" FK_column="CustomerID" crossRef="1" order="1" nullable="0" toXmlMode="1" convertorToPrimitive="" java.sql.Types="java.sql.Types.VARCHAR" remarks="No remarks for this field in the database (or the database driver doesn't return column remarks)." hasMore="1" />
<COLUMN name="CustomerTypeID" primaryKey="PK_CustomerCustomerDemo" primaryKeySeq="2" identity="0" javaType="String" asObject="" dbType="nchar" dbTypeDef="nchar(10)" dbSize="10" allocateVar="0" resultSetGetSet="String" FK_table="CustomerDemographics" FK_column="CustomerTypeID" crossRef="1" order="2" nullable="0" toXmlMode="1" convertorToPrimitive="" java.sql.Types="java.sql.Types.VARCHAR" remarks="No remarks for this field in the database (or the database driver doesn't return column remarks)." hasMore="0" />
<PRIMARYKEYS commaSep="CustomerID,CustomerTypeID" commaSepJavaType="String CustomerID,String CustomerTypeID">
<KEY column="CustomerID" pkName="PK_CustomerCustomerDemo" keySeq="1" hasMore="1">
<COLUMN name="CustomerID" primaryKey="PK_CustomerCustomerDemo" primaryKeySeq="1" identity="0" javaType="String" asObject="" dbType="nchar" dbTypeDef="nchar(5)" dbSize="5" allocateVar="0" resultSetGetSet="String" FK_table="Customers" FK_column="CustomerID" crossRef="1" order="1" nullable="0" toXmlMode="1" convertorToPrimitive="" java.sql.Types="java.sql.Types.VARCHAR" remarks="No remarks for this field in the database (or the database driver doesn't return column remarks)." />
</KEY>
<KEY column="CustomerTypeID" pkName="PK_CustomerCustomerDemo" keySeq="2" hasMore="0">
<COLUMN name="CustomerTypeID" primaryKey="PK_CustomerCustomerDemo" primaryKeySeq="2" identity="0" javaType="String" asObject="" dbType="nchar" dbTypeDef="nchar(10)" dbSize="10" allocateVar="0" resultSetGetSet="String" FK_table="CustomerDemographics" FK_column="CustomerTypeID" crossRef="1" order="2" nullable="0" toXmlMode="1" convertorToPrimitive="" java.sql.Types="java.sql.Types.VARCHAR" remarks="No remarks for this field in the database (or the database driver doesn't return column remarks)." />
</KEY>
</PRIMARYKEYS>
<CROSSREFERENCES>
<RELATIONSHIP name="FK_CustomerCustomerDemo" references="CustomerDemographics" helpStr="CustomerTypeID" commaSepFK="CustomerTypeID" commaSepJavaTypeFK="String CustomerTypeID" commaSepPK="CustomerTypeID" commaSepJavaTypePK="String CustomerTypeID">
<CROSSREFERENCE key_seq="1" update_rule="1" delete_rule="1" deferrability="7" pktable="CustomerDemographics" pkcolumn="CustomerTypeID" pkcolumnJavaType="String" pkNullable="0" pkcolumnJavaTypePrimitiveConverter="" fktable="CustomerCustomerDemo" fkcolumn="CustomerTypeID" fkcolumnJavaType="String" fkNullable="0" fkcolumnJavaTypePrimitiveConverter="" hasMore="0" />
</RELATIONSHIP>
<RELATIONSHIP name="FK_CustomerCustomerDemo_Customers" references="Customers" helpStr="CustomerID" commaSepFK="CustomerID" commaSepJavaTypeFK="String CustomerID" commaSepPK="CustomerID" commaSepJavaTypePK="String CustomerID">
<CROSSREFERENCE key_seq="1" update_rule="1" delete_rule="1" deferrability="7" pktable="Customers" pkcolumn="CustomerID" pkcolumnJavaType="String" pkNullable="0" pkcolumnJavaTypePrimitiveConverter="" fktable="CustomerCustomerDemo" fkcolumn="CustomerID" fkcolumnJavaType="String" fkNullable="0" fkcolumnJavaTypePrimitiveConverter="" hasMore="0" />
</RELATIONSHIP>
</CROSSREFERENCES>
</ROOT>
Contact : Konstantine Kougios at ariskk@otenet.gr with subject “OODB framework” and comments, questions , bugs found or suggestions.