The hasMany tag defines a relationship where an object has more than
one of the child object specified by this tag. For
example, a User might have several addresses.
There are two ways that hasMany relationships can be configured. The first is just like hasOne relationships except in the opposite direction. Rather than the parent object having a foreign key to the child object, the child object has the foreign key to the parent. To clarify, in your database you may have Customer table and an Address table with the following structure:
Customer Table
| Name | Type | Nullable | Default | Other |
|---|---|---|---|---|
| customerId | Int | No | PK / Identity | |
| username | Varchar(50) | No | ||
| password | Varchar(50) | No | ||
| firstName | Varchar(50) | No | ||
| lastName | Varchar(50) | No | ||
|
dateCreated |
DateTime |
No |
getDate() |
|
Address Table
| Name | Type | Nullable | Default | Other |
|---|---|---|---|---|
|
addressId |
Int |
No |
|
PK / Identity |
|
customerId |
Int |
No |
|
FK to Customer.customerId |
|
street1 |
Varchar(50) |
No |
|
|
|
street2 |
Varchar(50) |
Yes |
|
|
|
city |
Varchar(50) |
No |
|
|
|
state |
Varchar(50) |
No |
|
|
|
zip |
Varchar(10) |
No |
|
|
Without any configuration, an instance of a Customer Record will automatically have getters and setters for each of the fields in the table. However, with a little extra configuration you tell Reactor that your Customer has many Addresses by virtue of the customerId field in both tables. Here is an example of that configuration:
<reactor>
<objects>
<object
name="Customer">
<hasMany
name="Address">
<relate
from="customerId" to="customerId" />
</hasMany
>
</object>
<object
name="Address" />
</objects>
</reactor>
Note: All reactor generated methods with return objects lazy load the object. In other words the Iterator object is not instantiated until you call getAddressIterator(). Additionally these objects are cached. Calling getAddressIterator() two times will return the same instance of the Address Iterator.
<reactor>
<objects>
<object
name="Customer">
<hasMany
name="Address">
<relate
from="customerId" to="customerId" />
<relate
from="fooId" to="fooId" />
</hasMany>
</object>
<object
name="Address" />
</objects>
</reactor>
Customer Table
| Name | Type | Nullable | Default | Other |
|---|---|---|---|---|
| customerId | Int | No | PK / Identity | |
| username | Varchar(50) | No | ||
| password | Varchar(50) | No | ||
| firstName | Varchar(50) | No | ||
| lastName | Varchar(50) | No | ||
|
dateCreated |
DateTime |
No |
getDate() |
|
UserAddress Table
| Name | Type | Nullable | Default | Other |
|---|---|---|---|---|
|
userAddressId |
Int |
No |
|
PK / Identity |
|
customerId |
Int |
No |
|
FK to Customer.customerId |
|
addressId |
Int |
No |
|
FK to Address.addressId |
Address Table
| Name | Type | Nullable | Default | Other |
|---|---|---|---|---|
|
addressId |
Int |
No |
|
PK / Identity |
|
street1 |
Varchar(50) |
No |
|
|
|
street2 |
Varchar(50) |
Yes |
|
|
|
city |
Varchar(50) |
No |
|
|
|
state |
Varchar(50) |
No |
|
|
|
zip |
Varchar(10) |
No |
|
|
This type of table structure allows for multiple addresses to be related to multiple customer and vice versa.
In this type of situation you would define the linking object to have one of both the related objects. The parent object would have many of the child object via a link though the linking object. This link is accomplished with the link tag.
Here's an example:
<reactor>
<objects>
<object
name="Customer">
<hasMany
name="Address">
<link
name="Customer" />
</hasMany>
</object>
<object
name="CustomerAddress">
<hasOne
name="Customer">
<relate
from="customerId" to="customerId" />
</hasOne>
<hasOne
name="Address">
<relate
from="addressId" to="addressId" />
</hasOne>
</object>
<object
name="Address" />
</objects>
</reactor>
Now, when you create a Customer Record the object will have a getAddressIterator() method which will return an Iterator of address objects related to the Customer via the CustomerAddress table.
The hasMany tag has an optional alias argument. When not provided the alias defaults to the value of the name attribute. The alias argument controls how the methods generated from the relationship are named. For example, in the example above the Customer object hasMany Address objects. This causes the method name getAddressIterator() to be returned. If you wanted to rename this method to something else you can provide an alias on the relationship tag. If you provided an alias of "Location" the generated method would be named getLocatinIterator().
|
Attribute |
Required |
Description |
|---|---|---|
|
name |
yes |
The alias of the related object.
Note: If you did not specify an alias for the object that you are relating to, the alias is defaulted to the object's name. |
|
alias |
no |
The alias to assign to this relationship. When not provided this defaults to the value of the name attribute. |
|
Tag |
Required |
Description |
|---|---|---|
|
yes (if a link is not provided) |
Defines what fields that relate this object to the related object. | |
|
yes (if a relate is not provided) |
Defines the object which links this parent object to its child. |
<reactor>
<objects>
<object
name="Customer">
<hasone
name="Address">
<relate
from="addressId" to="addressId" />
</hasone>
</object>
<object
name="Address" />
</objects>
</reactor>