The examples below show extensions being used to map persistent classes to an existing schema. Remember, however, that you are free to let Kodo auto-generate the schema. In this case, you might still use a few extensions, but only to specify inverses for one-to-many relations, turn on ordering in collection or array fields, and customize the names of a few tables and columns in the event of naming conflicts.
For the purpose of this example, assume the following tables exist:
PERSON |========================================| | PK | NAME | SSNUM | MGR | |========================================| | 1 | john | 123-45-6789 | 3 | | 2 | fred | 987-65-4321 | 3 | | 3 | alice | 111-22-3333 | NULL | | ... | |========================================| PROJECT |============================================| | PK | START_DATE | END_DATE | CODE_NAME | |============================================| | 1 | 10 25 2000 | NULL | 2.0a1 | | 2 | 01 10 2001 | 01 31 2001| TestPhase1 | | ... | |============================================| XREF |==================| | PERSON | PROJECT | |==================| | 1 | 1 | | 2 | 1 | | 2 | 2 | |==================|
The representation of this data as java classes might look something like:
package com.solarmetric.examples; ... public class Person { private String name; private String social; private Person manager; private Collection managedPeople; private Collection projects; ... } public class Project { private String codeName; private Date start; private Date end; private List people; ... }
Given the above classes and tables, the metadata to map them together could be defined as follows:
<?xml version="1.0"?> <jdo> <package name="com.solarmetric.examples"> <class name="Person"> <extension vendor-name="kodo" key="table" value="PERSON"/> <extension vendor-name="kodo" key="pk-column" value="PK"/> <extension vendor-name="kodo" key="lock-column" value="none"/> <extension vendor-name="kodo" key="class-column" value="none"/> <field name="name"> <extension vendor-name="kodo" key="data-column" value="NAME"/> </field> <field name="social"> <extension vendor-name="kodo" key="data-column" value="SSNUM"/> </field> <field name="manager"> <extension vendor-name="kodo" key="data-column" value="MGR"/> </field> <!-- one-to-many mappings never take schema extensions; all the needed information is available from the related class and its inverse field --> <field name="managedPeople"> <collection element-type="Person"/> <extension vendor-name="kodo" key="inverse" value="manager"/> </field> <field name="projects"> <collection element-type="Project"/> <extension vendor-name="kodo" key="inverse" value="people"/> <extension vendor-name="kodo" key="table" value="XREF"/> <extension vendor-name="kodo" key="data-column" value="PROJECT"/> <extension vendor-name="kodo" key="ref-column" value="PERSON"/> </field> </class> <class name="Project"> <extension vendor-name="kodo" key="table" value="PROJECT"/> <extension vendor-name="kodo" key="pk-column" value="PK"/> <extension vendor-name="kodo" key="lock-column" value="none"/> <extension vendor-name="kodo" key="class-column" value="none"/> <field name="codeName"> <extension vendor-name="kodo" key="data-column" value="CODE_NAME"/> </field> <field name="start"> <extension vendor-name="kodo" key="data-column" value="START_DATE"/> </field> <field name="end"> <extension vendor-name="kodo" key="data-column" value="END_DATE"/> </field> <field name="people"> <collection element-type="Person"/> <extension vendor-name="kodo" key="inverse" value="projects"/> <extension vendor-name="kodo" key="table" value="XREF"/> <extension vendor-name="kodo" key="data-column" value="PERSON"/> <extension vendor-name="kodo" key="ref-column" value="PROJECT"/> </field> </class> </package> </jdo>
For the purpose of this example, assume the following tables exist:
COMPANIES |===========================| | CID | NAME | |===========================| | 1 | SolarMetric | | 2 | Cisco | | 3 | Sun Microsystems | | ... | |===========================| EMPS |=============================================| | EMP_ID | COMPID | FNAME | LNAME | |=============================================| | 1 | 1 | Abe | White | | 2 | 1 | Marc | Prud'hommeaux | | 3 | 1 | Patrick | Linksey | | 4 | 3 | Bill | Joy | | ... | |=============================================|
The representation of this data as java classes might look something like:
package com.solarmetric.examples; ... public class Employee { private String firstName; private String lastName; private Company company; ... } public class Company { private String name; private Set employees; ... }
The metadata for this mapping will take advantage of the "inverse" extension, which tells Kodo to skip the use of an intermediate cross-reference table and instead map directly to the traditional one-to-many mechanism commonly used in relational database schema design:
<jdo> <package name="samples.ormapping.oneToMany"> <class name="Company"> <extension vendor-name="kodo" key="table" value="COMPANIES"/> <extension vendor-name="kodo" key="pk-column" value="CID"/> <extension vendor-name="kodo" key="lock-column" value="none"/> <extension vendor-name="kodo" key="class-column" value="none"/> <field name="name"> <extension vendor-name="kodo" key="data-column" value="NAME"/> </field> <field name="employees"> <collection element-type="Employee"/> <extension vendor-name="kodo" key="inverse" value="company"/> </field> </class> <class name="Employee"> <extension vendor-name="kodo" key="table" value="EMPS"/> <extension vendor-name="kodo" key="pk-column" value="EMP_ID"/> <extension vendor-name="kodo" key="lock-column" value="none"/> <extension vendor-name="kodo" key="class-column" value="none"/> <field name="firstName"> <extension vendor-name="kodo" key="data-column" value="FNAME"/> </field> <field name="lastName"> <extension vendor-name="kodo" key="data-column" value="LNAME"/> </field> <field name="company"> <extension vendor-name="kodo" key="data-column" value="COMPID"/> </field> </class> </package> </jdo>
Now we will modify the example a bit for application identity. The new schema is:
PERSON |===================================================| | NAME (PK) | SSNUM (PK) | MGR_NAME | MGR_SSNUM | |===================================================| | john | 123-45-6789 | alice | 111-22-3333 | | fred | 987-65-4321 | alice | 111-22-3333 | | alice | 111-22-3333 | NULL | NULL | | ... | | |===================================================| PROJECT |==========================================| | START_DATE | END_DATE | CODE_NAME (PK) | |==========================================| | 10 25 2000 | NULL | 2.0a1 | | 01 10 2001 | 01 31 2001| TestPhase1 | | ... | |==========================================| XREF |==========================================| | PERSON_NAME | PERSON_SSNUM | PROJECT | |==========================================| | john | 123-45-6789 | 2.0a1 | | fred | 987-65-4321 | 2.0a1 | | alice | 111-22-3333 | TestPhase1 | |==========================================|
The classes remain unchanged. Application identity classes would have to be introduced for Person and Project, but those will not be shown here. To review, the classes representing the above tables are:
package com.solarmetric.examples; ... public class Person { private String name; private String social; private Person manager; private Collection managedPeople; private Collection projects; ... } public class Project { private String codeName; private Date start; private Date end; private List people; ... }
Given the above classes and tables, the metadata to map them together could now be defined as follows:
<?xml version="1.0"?> <jdo> <package name="com.solarmetric.examples"> <class name="Person" objectid-class="..."> <extension vendor-name="kodo" key="table" value="PERSON"/> <extension vendor-name="kodo" key="lock-column" value="none"/> <extension vendor-name="kodo" key="class-column" value="none"/> <field name="name" primary-key="true"> <extension vendor-name="kodo" key="data-column" value="NAME"/> </field> <field name="social" primary-key="true"> <extension vendor-name="kodo" key="data-column" value="SSNUM"/> </field> <field name="manager"> <extension vendor-name="kodo" key="name-data-column" value="MGR_NAME"/> <extension vendor-name="kodo" key="social-data-column" value="MGR_SSNUM"/> </field> <!-- one-to-many mappings never take schema extensions; all the needed information is available from the related class and its inverse field --> <field name="managedPeople"> <collection element-type="Person"/> <extension vendor-name="kodo" key="inverse" value="manager"/> </field> <field name="projects"> <collection element-type="Project"/> <extension vendor-name="kodo" key="inverse" value="people"/> <extension vendor-name="kodo" key="table" value="XREF"/> <extension vendor-name="kodo" key="codeName-data-column" value="PROJECT"/> <extension vendor-name="kodo" key="name-ref-column" value="PERSON_NAME"/> <extension vendor-name="kodo" key="social-ref-column" value="PERSON_SSNUM"/> </field> </class> <class name="Project" objectid-class="..."> <extension vendor-name="kodo" key="table" value="PROJECT"/> <extension vendor-name="kodo" key="lock-column" value="none"/> <extension vendor-name="kodo" key="class-column" value="none"/> <field name="codeName" primary-key="true"> <extension vendor-name="kodo" key="data-column" value="CODE_NAME"/> </field> <field name="start"> <extension vendor-name="kodo" key="data-column" value="START_DATE"/> </field> <field name="end"> <extension vendor-name="kodo" key="data-column" value="END_DATE"/> </field> <field name="people"> <collection element-type="Person"/> <extension vendor-name="kodo" key="inverse" value="projects"/> <extension vendor-name="kodo" key="table" value="XREF"/> <extension vendor-name="kodo" key="name-data-column" value="PERSON_NAME"/> <extension vendor-name="kodo" key="social-data-column" value="PERSON_SSNUM"/> <extension vendor-name="kodo" key="codeName-ref-column" value="PROJECT"/> </field> </class> </package> </jdo>