JDO : 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.

The various possible relationships are described below.

For RDBMS a 1-1 relation is stored as a foreign-key column(s). For non-RDBMS it is stored as a String "column" storing the 'id' (possibly with the class-name included in the string) of the related object.


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 XML metadata for these classes as follows

<package name="mydomain">
    <class name="User" table="USER">
        <field name="id" primary-key="true">
            <column name="USER_ID"/>
        </field>
        ...
    </class>

    <class name="Account" table="ACCOUNT">
        <field name="id" primary-key="true">
            <column name="ACCOUNT_ID"/>
        </field>
        ...
        <field name="user">
            <column name="USER_ID"/>
        </field>
    </class>
</package>

or alternatively using annotations

public class Account
{
    ...

    @Column(name="USER_ID")
    User user;
}

public class User
{
    ...
}

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 :-

  • Account has the object reference (and so owns the relation) to User and so its table holds the foreign-key
  • 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.
  • If you invoke an operation that will retrieve the one-to-one field, and you only want it to get the foreign key value (and not join to the related table) you can add the metadata extension fetch-fk-only (set to "true") to the field/property.

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.


Here we create the 1-1 relationship with a single foreign-key. To do this you define the XML metadata as

<package name="mydomain">
    <class name="User" table="USER">
        <field name="id" primary-key="true">
            <column name="USER_ID"/>
        </field>
        ...
        <field name="account" mapped-by="user"/>
    </class>

    <class name="Account" table="ACCOUNT">
        <field name="id" primary-key="true">
            <column name="ACCOUNT_ID"/>
        </field>
        ...
        <field name="user">
            <column name="USER_ID"/>
        </field>
    </class>
</package>

or alternatively using annotations

public class Account
{
    ...

    @Column(name="USER_ID")
    User user;
}

public class User
{
    ...

    @Persistent(mappedBy="user")
    Account account;
}
The difference is that we added mapped-by to the field of User. This represents the bidirectionality.

This will create 2 tables in the database, one for User (with name USER), and one for Account (with name ACCOUNT). With RDBMS the ACCOUNT table will have a column USER_ID (since RDBMS will place the FK on the side without the "mapped-by"). Like this



With non-RDBMS datastores both tables will have a column containing the "id" of the related object, that is USER will have an ACCOUNT column, and ACCOUNT will have a USER_ID column.

Things to note :-

  • When forming the relation please make sure that you set the relation at BOTH sides since DataNucleus would have no way of knowing which end is correct if you only set one end.
  • If you invoke an operation that will retrieve the one-to-one field (of the non-owner side), and you only want it to get the foreign key value (and not join to the related table) you can add the metadata extension fetch-fk-only (set to "true") to the field/property.

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.