An aggregated field is in some respects similar to a one-to-one relationship mapping. As in that, it references a set of data from an referenced object. Contrary to the normal one-to-one-mapping, an aggregated object doesn't have its own primary key, and it is supposed to be stored directly into the database table. Another difference lies in the life-cycle. Because a aggregated object has no primary key, it cannot live outside of its parent object. As long as the parent object exists, as long the aggregated object lives too. As soon as the parent object is destroyed, the aggregated object vanishes too.
Aggregated objects are contained in the parent object, i.e. it is not possible that an aggregated object reference becomes null. This does not mean that the attributes of the aggregated referenced object may not become null.
Aggregated objects do not need to be enhanced as persistent capable objects. And you do not need to write special metadata e.g. in a JDO file. You may, however, specify how the fields of an aggregated object are to be stored in the database. The default table, where an aggregated object is stored, is the table of the container element. In order to store aggregated objects in another table, you may have to use multi-table keys, as specified in the mapping of one persistent object to multiple tables.
The following example shows how to use aggregated mappings:
As container object we use the class Article, which has two money values, i.e. grossPrice and netPrice . Each money value stores a numerical monetary value and the currency of this value is. This gives us the following classes:
public class Article
{
...
private MoneyValue grossPrice;
private MoneyValue netPrice;
...
public MoneyValue getGrossPrice ()
{
return grossPrice;
}
public MoneyValue getNetPrice ()
{
return netPrice;
}
...
public void setGrossPrice (MoneyValue value)
{
grossPrice = value;
}
public void setNetPrice (MoneyValue value)
{
netPrice = value;
}
...
}
The class MoneyValue :
public class MoneyValue
{
...
private double value;
private String currency;
...
public double getValue ()
{
return value;
}
public String getCurrency ()
{
return currency;
}
public void setValue (double aValue)
{
value = aValue;
}
public void setCurrency (String aValue)
{
currency = aValue;
}
...
}
To map this for usage with intelliBO, we define the fields grossPrice and netPrice of class Article as persistent with an aggregated mapping type. You either may specify the field mappings explicitly, or you may use the implicit mapping provided by intelliBO.
If you map the fields explicitly, you may specify the field name of the field of the aggregated object and the database table and database field name where to store the values. Additionally you may specify the SQL type of the database field.
To specify an aggregated mapping, you have to specify the element type of the aggregation. In the element-type extension you specify the Java class, which should be used. This class should follow basic guidelines for dynamic creation of Java objects, namely the class should have a public empty default constructor (or the implicit default constructor which is used if no special constructor is defined).
The implicit mapping uses otherwise specified metadata, e.g. a naming rule about how to translate class and field names from the object model to table and field names of the database model. Because currently there is no naming rule mechanism for providing aggregated names, instead the fixed rule "field name" + "_" + "aggregated field name" is used. This means that e.g. for the given model the fieldname "grossPrice_value" is used. This name is applied to define the final database field name, using a naming rule, if existent.
The implicit mapping can be used as follows:
<?xml version="1.0" encoding="UTF-8"?>
<jdo xmlns="http://java.sun.com/xml/ns/jdo/jdo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/jdo/jdo http://java.sun.com/xml/ns/jdo/jdo_2_0.xsd">
<package name="com.signsoft.test">
<class identity-type="datastore" name="Article">
...
<field name="netPrice" persistence-modifier="persistent">
<extension key="jdbc" vendor-name="ssibo">
<extension key="mapping" value="aggregated" vendor-name="ssibo">
<extension key="element-type" value="com.signsoft.test.MoneyValue" vendor-name="ssibo"/>
</extension>
</extension>
</field>
<field name="grossPrice" persistence-modifier="persistent">
<extension key="jdbc" vendor-name="ssibo">
<extension key="mapping" value="aggregated" vendor-name="ssibo">
<extension key="element-type" value="com.signsoft.test.MoneyValue" vendor-name="ssibo"/>
</extension>
</extension>
</field>
...
</class>
</package>
</jdo>
If you do not specify other elements, all declared fields of the aggregated class will be mapped. You may explicitly specify the aggregated field mappings to override the automatically used mapping data. To do so, you should provide at least the field name and column name used in the database. Additionally you may specify the database table and the SQL result type.
<?xml version="1.0" encoding="UTF-8"?>
<jdo xmlns="http://java.sun.com/xml/ns/jdo/jdo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/jdo/jdo http://java.sun.com/xml/ns/jdo/jdo_2_0.xsd">
<package name="com.signsoft.test">
<class identity-type="datastore" name="Article">
...
<field name="netPrice" persistence-modifier="persistent">
<extension key="jdbc" vendor-name="ssibo">
<extension key="mapping" value="aggregated" vendor-name="ssibo">
<extension key="element-type" value="com.signsoft.test.MoneyValue" vendor-name="ssibo"/>
<extension key="field" vendor-name="ssibo">
<extension key="field-name" value="value" vendor-name="ssibo"/>
<extension key="db-field-name" value="FNETPRICE_VALUE" vendor-name="ssibo"/>
</extension>
<extension key="field" vendor-name="ssibo">
<extension key="field-name" value="currency" vendor-name="ssibo"/>
<extension key="db-field-name" value="FNETPRICE_CURRENCY" vendor-name="ssibo"/>
</extension>
</extension>
</extension>
</field>
<field name="grossPrice" persistence-modifier="persistent">
<extension key="jdbc" vendor-name="ssibo">
<extension key="mapping" value="aggregated" vendor-name="ssibo">
<extension key="element-type" value="com.signsoft.test.MoneyValue" vendor-name="ssibo"/>
<extension key="field" vendor-name="ssibo">
<extension key="field-name" value="value" vendor-name="ssibo"/>
<extension key="db-field-name" value="FGROSSPRICE_VALUE" vendor-name="ssibo"/>
<extension key="db-table-name" value="TARTICLE " vendor-name="ssibo"/>
</extension>
<extension key="field" vendor-name="ssibo">
<extension key="field-name" value="currency" vendor-name="ssibo"/>
<extension key="db-field-name" value="FGROSSPRICE_CURRENCY" vendor-name="ssibo"/>
<extension key="sql-type" value="CLOB" vendor-name="ssibo"/>
</extension>
</extension>
</extension>
</field>
...
</class>
</package>
</jdo>
In order to avoid the mapping of fields in an aggregated class, you may also specify the persistence-modifier . This key may take on of the two values " persistent " or " not
persistent ", e.g. like in:
<extension key="field" vendor-name="ssibo"> <extension key="field-name" value="currency" vendor-name="ssibo"/> <extension key="persistence-modifier" value="persistent" vendor-name="ssibo"/> </extension> <extension key="field" vendor-name="ssibo"> <extension key="field-name" value="exchange-rate" vendor-name="ssibo"/> <extension key="persistence-modifier" value="not persistent" vendor-name="ssibo"/> </extension>In your application you may use an aggregated field as any other reference, e.g. like the following:
Article article = new Article();
article.setName ("Article 1");
MoneyValue mv1 = new MoneyValue();
mv1.setValue(125);
mv1.setCurrency("EUR");
MoneyValue mv2 = new MoneyValue();
mv2.setValue(130);
mv2.setCurrency("CHF");
article.setNetPrice(mv1);
article.setGrossPrice(mv2);
pm.makePersistent(article);