Reactor has a few other tricks up its sleeves too. For instance, what if you wanted to know all the Customers associated with an address? Piece of cake! In this case, because one address can be associated with many Customers, an address "has many" customers. To facilitate this we'll add a hasMany relationship to our Reactor.xml configuration file.
<reactor>
<config>
<project
value="Scratch" />
<dsn
value="Scratch" />
<type
value="mssql" />
<mapping
value="/ScratchData" />
<mode
value="development" />
</config>
<objects>
<object
name="Customer">
<hasOne
name="Address">
<relate
from="addressId" to="addressId" />
</hasOne>
</object>
<object
name="Address">
<hasMany
name="Customer">
<relate
from="addressId" to="addressId" />
</hasMany>
</object>
</objects>
</reactor>
This update has added a new object tag for the Address table to our configuration. This Address object has a "hasMany" tag that relates the Address to Customers via the addressId column in both tables.
So, if we create an AddressRecord object we'll see a new method on it. Go ahead and do that now. I'll wait for you to get back. Let me know what methods are new.
… Long Pause …
Ok. What'd you find? Ah ha! You're correct. The hasMany relationship caused one method to be generated: getCustomerIterator()
Without getting into too much detail, this method returns an object that allows you to easily iterate over and manipulate sets of related Records. In this case it represents the Address' Customers.
The Iterator object has several methods of note. We'll first focus on getQuery() and getArray(). GetQuery() returns a query of the related customers. GetArray() returns an array of CustomerRecords. Both of these methods accept optional arguments to limit the scope of the data returned. The signature of these two methods are:
query = getQuery(from, count)
array= getArray(from, count)
In both methods from and count are optional. From is the first row to return. Count is the number of rows to return.
For example, the following code will return a query of all the customers related to an AddressRecord:
<cfset customers = AddressRecord.getCustomerIterator().getQuery() />
The next example will return only 5 records starting from the 10th record.
<cfset customers = AddressRecord.getCustomerIterator().getQuery(10, 5) />
If the from and count arguments do not define a valid range then anything out side of the range will not be returned.
Using the from and count is particularly useful when working with paginated lists of data. In fact, the Iterator object has methods for sorting and filtering data. The end result is the Iterator enables you to create applications which include sorting, filtering and paginating data.
The getArray() method works just the same as the getQuery() method, but it returns an array of records.
Note: Iterators are backed by ColdFusion queries. Calling getArray() translates rows in the query into record objects which are cached inside the Iterator. This means that even if you have a query of several thousand objects it's not terribly expensive to use getArray() with the from and count arguments to translate a small subset of data into records.
However, if you call getArray()
without the from and to arguments on anything more than a small set of
data you may run into performance problems.
Unlike the hasOne relationships, there is no setCustomerIterator() method on the Address. This is because there's really nothing to set from the Address' perspective. The address doesn't have a field for customerId.
This all leads up to the next relationship type, Relationships via Linking Tables.