JPOX
JPOX
 Project  |  Ver 1.1  |  Ver 1.2  |  JDO  |  JPA  |  Guides  |  Tools
1.1 | Preparation | O/R Mapping | Runtime | Extensions | Developer
O/R Mapping
Relationships
1-1 Relationships

You have a 1-to-1 relationship when an object of a class has an associated object of another class (only one associated object). It could also be between an object of a class and another object of the same class (obviously). You can create the relationship in 2 ways depending on whether the 2 classes know about each other (bidirectional), or whether only one of the classes knows about the other class (unidirectional). These are described below.



Unidirectional

For this case you could have 2 classes, User and Account, as below.



so the Account class knows about the User class, but not vice-versa. If you define the Meta-Data for these classes as follows

<package name="mydomain">
    <class name="User" table="USER">
        <field name="id" primary-key="true">
            <column name="USER_ID"/>
        </field>
        <field name="login">
            <column name="LOGIN" length="20" jdbc-type="VARCHAR"/>
        </field>
    </class>

    <class name="Account" table="ACCOUNT">
        <field name="id" primary-key="true">
            <column name="ACCOUNT_ID"/>
        </field>
        <field name="firstName">
            <column name="FIRSTNAME" length="50" jdbc-type="VARCHAR"/>
        </field>
        <field name="secondName">
            <column name="SECONDNAME" length="50" jdbc-type="VARCHAR"/>
        </field>
        <field name="user" persistence-modifier="persistent">
            <column name="USER_ID"/>
        </field>
    </class>
</package>

This will create 2 tables in the database, one for User (with name USER), and one for Account (with name ACCOUNT and a column USER_ID), as shown below.



Things to note :-

  • If you wish to specify the names of the database tables and columns for these classes, you can use the attribute table (on the class element) and the attribute name (on the column element)
  • JPOX does not currently support this relationship where the "User" end in the above example uses the "subclass-table" inheritance strategy.
  • If you call PM.deletePersistent() on the end of a 1-1 unidirectional relation without the relation and that object is related to another object, an exception will typically be thrown (assuming the RDBMS supports foreign keys). To delete this record you should remove the other objects association first.


Bidirectional

For this case you could have 2 classes, User and Account again, but this time as below. Here the Account class knows about the User class, and also vice-versa.



There are two ways to model this relationship.

Single foreign key

The first way will create the 1-1 relationship with a single foreign-key. To do this you define the MetaData as

<package name="mydomain">
    <class name="User" table="USER">
        <field name="id" primary-key="true">
            <column name="USER_ID"/>
        </field>
        <field name="login">
            <column name="LOGIN" length="20" jdbc-type="VARCHAR"/>
        </field>
        <field name="account" persistence-modifier="persistent" mapped-by="user">
        </field>
    </class>

    <class name="Account" table="ACCOUNT">
        <field name="id" primary-key="true">
            <column name="ACCOUNT_ID"/>
        </field>
        <field name="firstName">
            <column name="FIRSTNAME" length="50" jdbc-type="VARCHAR"/>
        </field>
        <field name="secondName">
            <column name="SECONDNAME" length="50" jdbc-type="VARCHAR"/>
        </field>
        <field name="user" persistence-modifier="persistent">
            <column name="USER_ID"/>
        </field>
    </class>
</package>

The difference is that we added mapped-by to the field of User. This will create 2 tables in the database, one for User (with name USER), and one for Account (with name ACCOUNT including a USER_ID). The fact that we specified the mapped-by on the User class means that the foreign-key is created in the ACCOUNT table. This mode of operation is only supported by JPOX for version 1.1.0-beta-3 onwards.

Things to note :-

  • When forming the relation please make sure that you set the relation at BOTH sides since JPOX would have no way of knowing which end is correct if you only set one end.




[If you wish to specify the names of the database tables and columns for these classes, you can use the attribute table (on the class element) and the attribute name (on the column element)].

Two foreign keys

The second way will create the 1-1 relationship with 2 unique foreign-keys, one from Account to User, and one from User to Account. So the relationship is like 2 independent 1-1 unidirectional relations. To do this you define the MetaData as

<package name="mydomain">
    <class name="User" identity-type="datastore">
        <field name="login" persistence-modifier="persistent">
            <column length="20" jdbc-type="VARCHAR"/>
        </field>
        <field name="account" persistence-modifier="persistent">
        </field>
    </class>

    <class name="Account" identity-type="datastore">
        <field name="firstName" persistence-modifier="persistent">
            <column length="50" jdbc-type="VARCHAR"/>
        </field>
        <field name="secondName" persistence-modifier="persistent">
            <column length="50" jdbc-type="VARCHAR"/>
        </field>
        <field name="user" persistence-modifier="persistent">
        </field>
    </class>
</package>

This will create 2 tables in the database, one for User (with name USER including a ACCOUNT_ID to link to the ACCOUNT table), and one for Account (with name ACCOUNT including a USER_ID).



If the database does not support defered constraints and primary-key columns are auto assigned by the database, the foreign-key columns must be NULLABLE. This is due to the fact that JPOX will insert both sides of the relationship in the tables before knowing the identifiers of both sides, thus after the insert an update statement is fired to update on of the sides of the relationship. Like the following example:

_USER_ID    = INSERT INTO USER    ( LOGIN, ACCOUNT_ID )              VALUES ( 'user', NULL )
_ACCOUNT_ID = INSERT INTO ACCOUNT ( FIRSTNAME, SECONDNAME, USER_ID ) VALUES ( 'firstName', 'secondName', _USER_ID )
              UPDATE USER SET ACCOUNT_ID=_ACCOUNT_ID WHERE USER_ID = _USER_ID


Embedded

The above 2 relationship types assume that both classes in the 1-1 relation will have their own table. You can, of course, embed the elements of one class into the table of the other. This is described in Embedded PC Objects.