Aggregated Collection Mapping

An aggregated collection provides the possibility to represent the values stored in a set of database fields as a Java Collection to the client. This means, you may define, that the fields can be accessed as an java.util.Collection ( java.util.List,java.util.Set ) or an Array datatype.

Contrary to a normal collection type mapping (one-to-many or many-to-many mapping), an aggregated collection mapping does not manage its own data, like e.g. the references in the above mentioned mappings. Another difference lies in the life-cycle. Because aggregated collections have no own data or keys beside of the actual data, it cannot live outside of its parent object. As long as the parent object exists, as long the aggregated collection lives too. As soon as the parent object is destroyed, the aggregated collection vanishes too. This process is implicit and cannot be triggered programmatically, like in the normal collection mappings (e.g. by the cascade-delete mechanism).

Aggregated collections are contained in the parent object, i.e. it is not possible that an aggregated collection becomes null. A null value in a database field mapped with an aggregated collection mapping is ignored, the resulting array is filled with the next available valid object.

The maximum size of the collection is specified at mapping time, the collection cannot contain more elements than you assigned fields to the mapping. Collections should not contain holes, i.e. null values. Existing null values in collections are ignored and not stored to the database.

There is no guarantee about order of the elements in an aggregated collection mapping. The mapped database fields are used as seemed appropriate, which may include remapping of collection entry values to database fields.

A aggregated collection may only contain objects of a type and only of simple types. Not supported complex types are custom objects, persistent capable objects or references on it and nested collections. There is no simple way to change the database representation of a collection element.

If you map collection elements, you may use other tables as storage, if you define proper multi-table key. For each collection element you normally specify the internal field name and the database field name. Additionally you may specify a table name, which overrides the default table name. You may specify a SQL type for the collection element. This SQL type should be compatible to the element type of the collection.

The following examples show a possible use of an aggregate collection mapping. As container object we use the class Person , which has a primary key, a name and a list of hobbies. The hobbies are stored as normal strings, like in "Diving", "Reading" a.s.o.. This gives us the following class:

public class Person
{
  public Person() 
  {
  }

  private int id;
  private String name;
  private List hobbies = new ArrayList();

  public int getId() { return id; }
  public String getName() { return name; }
  public List getHobbies() { return hobbies; }

  public void setId (int value) { id = value; }
  public void setName (String value) { name = value; }
  public void setHobbies (List value) { hobbies = value; }
}
In order to use persistent objects in intelliBO, we map the class data (default table) and the fields id and name as usual. The field hobbies is mapped as persistent field with aggregated collection mapping . You have to explicitly define the field mappings.

Additional data for the mapping may be the element-type , i.e. the type of the collection elements, and the result-type , which defines the type of the resulting collection. Here you may either specify the name of a class which implements java.util.Collection or a collection type.

There exist a little redundancy in that it is possible to specify the element-type in either a JDO compatible way or in a Signsoft intelliBO specific way. You may specify the element in both ways. But take care, that the values do not contradict themselves.

The JDO compatible way of specifying the element type is as follows:

<field name="hobbies">
  <collection element-type="String"/>
  ...
</field>
The Signsoft compatible way would be to specify the element-type in the intelliBO JDBC vendor extensions, like in:
<field name="hobbies">
  <extension key="jdbc" vendor-name="ssibo">
    <extension key="mapping" value="aggregated-collection" vendor-name="ssibo">
      <extension key="element-type" value="String" vendor-name="ssibo"/>
    </extension>
  </extension>
</field>
The following shows the full mapping for the sample business object:
<class name="Person">
...
  <field name="hobbies" persistence-modifier="persistent">
    <collection element-type="String"/>
    <extension key="jdbc" vendor-name="ssibo">
      <extension key="mapping" value="aggregated-collection" vendor-name="ssibo">
        <extension key="result-type" value="java.util.ArrayList" vendor-name="ssibo"/>
        <extension key="field" vendor-name="ssibo">
          <extension key="field-name" value="hobby1" vendor-name="ssibo"/>
          <extension key="db-field-name" value="FHOBBY1" vendor-name="ssibo"/>
        </extension>
        <extension key="field" vendor-name="ssibo">
          <extension key="field-name" value="hobby2" vendor-name="ssibo"/>
          <extension key="db-field-name" value="FHOBBY2" vendor-name="ssibo"/>
        </extension>
        <extension key="field" vendor-name="ssibo">
          <extension key="field-name" value="hobby3" vendor-name="ssibo"/>
          <extension key="db-field-name" value="FHOBBY3" vendor-name="ssibo"/>
        </extension>
        <extension key="field" vendor-name="ssibo">
          <extension key="field-name" value="hobby4" vendor-name="ssibo"/>
          <extension key="db-field-name" value="FHOBBY4" vendor-name="ssibo"/>
        </extension>
        ...
      </extension>
    </extension>
  </field> 
</class>
In your application, you may use an aggregated collection field as any other collection, e.g. like the following:
Person p = new Person();
p.setName("test1");
List hobbies = new ArrayList();

hobbies.add("fishing");
hobbies.add("reading");
hobbies.add("music");
hobbies.add("sports");

p.setHobbies(hobbies);
pm.makePersistent(p);
Please note the following limitation: exchange operations are not supported, neither for the collection not for the collection elements.