Many-To-Many Relation Mapping

This relationship type extends the one-to-many relations by the ability to assign from one tables row to more than one row from the other table and vice versa. These relations are stored in a separate third table, the so-called lookup table. Both source tables do not contain any information that deals with relations.

To continue our example, we have to assign any number of addresses to a person and any number of persons to an address.

The table structure now looks like this:

Database Table TPERSON:

FieldUsage
FKEYperson's primary key
FLASTNAMEperson's last name
FFIRSTNAMEperson's first name

Note that there are no columns dealing with addresses.

Database Table TADDRESS:

FieldUsage
FKEYaddresses' primary key
FSTREETaddresses' street name
FCITYaddresses' city name

Note that there are no columns dealing with persons.

Database Table TPERSADDR:

FieldUsage
FPERSKEYprimary key for one person
FADDRKEYprimary key for one address

The relation between the tables TPERSON and TADDRESS is defined using a lookup table TPERSADDR. This table stores only relations between rows of the first two tables. Any number of relations is possible. The primary key of every table, which is part of the relation, is stored here.

Within the class structure itself, the third table is not reflected. The person's connection to an address is still the same - a one-to-many relationship. But an address is no longer connected to a single person. Instead it is connected to any number of persons. This must be considered in the application's logic, but makes no difference to the implementation of the class itself.

The class Person is the same as in the one-to-many implementation. The class Address remains the same too.

As in the one-to-many implementation, the attribute addr must be defined as a Collection in the JDO file. Besides that, the element-type must be declared. The result-type is an implementation of the Collection interface, as in one-to-many relations.

All three tables must now be used in the nested extensions of the mapping-extension of the addr field, because they are all part of the whole relation. But because the relationship is reflected only from the view of the Person class and because no back-reference is set, the change appears only within the definition of class Person .

The relationship between the classes and the tables is defined in the mapping-extension with the value " many-to-many ". Potential nested extensions of this mapping are the same as in the mapping-extension of the one-to-many mapping except the reference -extension. The specification of the source and destination joins can be defined independently. You may use different numbers of primary key fields on both sides. So different joins for the source and destination side of the lookup-table can be specified for more flexibility.

The relations between the tables are described by the following extensions instead of the reference-extension:

ExtensionDescriptionDefault value
src-tablethe name of the table containing the referencing objectthe table name defined for the class
dst-tablethe name of the table containing the referenced objectextracted from field type name using naming rules
lookup-tablethe name of the lookup table used for this mappinggenerated using naming rules
src-referencelist of source reference fields
src-fieldthe name of the field that contains the used reference valueextracted from field name using naming rules
sql-typethe SQL type (only necessary if the database is not able to detect the correct type)automatic detection
dst-fieldthe name of the field where the reference value is stored (lookup table)automatic detection
dst-referencelist of destination reference fields

The JDO file for the Person:

<class name="Person" ...>
  ...
  <field name="key" ...>...
  <field name="lastName"...>....
  <field name="firstName"...>....
  <field name="addr">
    <collection element-type="com.test.Address"/>
      <extension vendor-name="ssibo" key="jdbc">
      <extension vendor-name="ssibo" key="mapping" value="many-to-many">
        <extension vendor-name="ssibo" key="result-type" value="java.util.ArrayList"/>
        <extension vendor-name="ssibo" key="cascade-delete" value="true"/>
        <extension vendor-name="ssibo" key="src-table" value="TPERSON"/>
        <extension vendor-name="ssibo" key="dst-table" value="TADDRESS"/>
        <extension vendor-name="ssibo" key="lookup-table" value="TPERSADDR"/>
        <extension vendor-name="ssibo" key="src-reference">
          <extension vendor-name="ssibo" key="src-field" value="FKEY"/>
          <extension vendor-name="ssibo" key="dst-field" value="FPERSKEY"/>
        </extension>
        <extension vendor-name="ssibo" key="dst-reference">
          <extension vendor-name="ssibo" key="src-field" value="FADDRKEY"/>
          <extension vendor-name="ssibo" key="dst-field" value="FKEY"/>
        </extension>
      </extension>
    </extension>
  </field>
</class>

Sample application:

//Creation of two persons
Person p1 = new Person();Angabe der Rückreferenz 
p1.setLastName("Smith");
pm.makePersistent(p1);

Person p2 = new Person();
p2.setLastName("Miller");
pm.makePersistent(p2);

// Creation of two addresses
Address a1 = new Address();
a1.setCity("New York");
Address a2 = new Address();
a2.setCity("Boston");

// Assigning the addresses to the persons
p1.getAddresses().add(a1);
p1.getAddresses().add(a2);
p2.getAddresses().add(a2);

...

// Reading the addresses of the persons
List list = p1.getAddresses();
for (int i = 0; i < list.size(); i++)
{
  Address a = (Address) list.get(i);
  System.out.println(a.getCity());
}
...

Bidirectional Relation

A many-to-many relation is already bidirectional, so no additional settings are needed. The elements inverse and reverse-relation are not valid for many-to-many mappings.