|
You have a M-to-N (or Many-to-Many) relationship if an object of a class A has associated objects of class B,
and class B has associated objects of class A. This relationship may be achieved through Java Set, Map, List
or subclasses of these, although the only one that supports a true M-N is for a Set/Collection.
With DataNucleus this can be set up as described in this section, using what is called a
Join Table
relationship. Let's take the following example and describe how to model it with the different types of
collection classes. We have 2 classes,
Product
and
Supplier
as below.
Here the
Product
class knows about the
Supplier
class. In addition the
Supplier
knows
about the
Product
class, however with DataNucleus (as with the majority of JDO implementations) these
relationships are independent.
If you define the Meta-Data for these classes as follows
<package name="mydomain">
<class name="Product" identity-type="datastore">
...
<field name="suppliers" persistence-modifier="persistent" table="PRODUCTS_SUPPLIERS">
<collection element-type="mydomain.Supplier"/>
<join>
<column name="PRODUCT_ID"/>
</join>
<element>
<column name="SUPPLIER_ID"/>
</element>
</field>
</class>
<class name="Supplier" identity-type="datastore">
...
<field name="products" persistence-modifier="persistent" mapped-by="suppliers">
<collection element-type="mydomain.Product"/>
</field>
</class>
</package>
Note how we have specified the information only once regarding join table name, and join column names
as well as the <join>. This is the JDO standard way of specification, and results in a single join table.
See also :-
Firstly a true M-N relation with Lists is impossible since there are two lists, and it is
undefined as to which one applies to which side etc. What is shown below is two independent
1-N unidirectional join table relations.
If you define the Meta-Data for these classes as follows
<package name="mydomain">
<class name="Product" identity-type="datastore">
...
<field name="suppliers" persistence-modifier="persistent">
<collection element-type="mydomain.Supplier"/>
<join/>
</field>
</class>
<class name="Supplier" identity-type="datastore">
...
<field name="products" persistence-modifier="persistent">
<collection element-type="mydomain.Product"/>
<join/>
</field>
</class>
</package>
There will be 4 tables, one for
Product
, one for
Supplier
, and the join tables. The difference from the
Set example is in the contents of the join tables. An index column is added to keep track of the position of objects
in the Lists.
In the case of a List at both ends it doesn't make sense to use a single join table because the ordering
can only be defined at one side, so you have to have 2 join tables.
If you define the Meta-Data for these classes as follows
<package name="mydomain">
<class name="Product" identity-type="datastore">
...
<field name="suppliers" persistence-modifier="persistent">
<map key-type="java.lang.String" value-type="mydomain.Supplier"/>
<join/>
</field>
</class>
<class name="Supplier" identity-type="datastore">
...
<field name="products" persistence-modifier="persistent">
<map key-type="java.lang.String" value-type="mydomain.Product"/>
<join/>
</field>
</class>
</package>
This will create 4 tables in the datastore, one for
Product
, one for
Supplier
, and the join tables
which also contains the keys to the Maps (a String).
Please be aware of the following.
-
To add an object to an M-N relationship you need to set it at both ends of the relation since the relation
is bidirectional and without such information the JDO implementation won't know which end of the relation
is correct.
-
If you want to delete an object from one end of a M-N relationship you will have to remove it first from
the other objects relationship. If you don't you will get an error message that the object to be deleted
has links to other objects and so cannot be deleted.
|
|