<hasOne > tag

Description

The hasOne tag defines a relationship where a parent object has one of a child object.  This relationship is useful in cases where the parent object is related to a child object via a foreign key.  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()

 

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

 

 

 

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 one Address by virtue of the addressId field in both tables.  Here is an example of that configuration:

 

<reactor>
 <objects>
   <object name="Customer">
     <hasOne name="Address">
       <relate from="addressId" to="addressId" />
     </hasOne>
   </object>

   <object name="Address" />
 </objects>
</reactor>

 
Now, when you generate the Customer Record it will not have these additional methods:
 
 

Note: all reactor generated methods with return objects lazy load the object.  In other words the Address object is not instantiated or read from the database until you call getAddress().  Additionally these objects are cached.  Calling getAddress() two times will return the same instance of the address.

 
The hasOne tag has one child tag, relate, which specify the fields which relate the two objects.  You can nest multiple relate tags to indicate that the relationship between the objects depends on multiple fields.  For example:
 

<reactor>
 <objects>
   <object name="Customer">
     <hasOne name="Address">
       <relate from="addressId" to="addressId" />
       <relate from="fooId" to="fooId" />
     </hasOne>
    </object>

    <object name="Address" />
 </objects>
</reactor>

 
This example shows that the Customer is related by two columns to the Address, addressId and fooId which exist in both tables.  This feature is useful when you have compound foreign keys defined in your database.
 
The hasOne 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().
 
Unlike the relate tag, you can express multi-step relationships by providing multiple link tags.
 
Another feature of the hasOne relationship is the use of "shared keys".  Shared keys are useful when the field being related is the primary key on both objects.  For example, consider a situation where you have a core type of user.  However, you might have variations on this type of user, each which collect their own data.  Consider these tables as an example:
 

User Table

 

Name Type Nullable Default Other
userId Int No   PK / Identity
username Varchar(50) No    
password Varchar(50) No    
firstName Varchar(50) No    
lastName Varchar(50) No    

dateCreated

DateTime

No

getDate()

 

 

Physician Table

 

Name Type Nullable Default Other
physicianId Int No   PK / FK to User.userId

licensedState

Varchar(10)

No

 

 

 
Developer Table
 
Name Type Nullable Default Other

developerId

Int No   PK / FK to User.userId

language

Varchar(50)

No

 

 

likesCoffee

Bit

No

1

 

 
As you can see, the Physician and Developer table's primary key values are not identity or auto number values.  Instead, they are foreign keys to the user table.  This means that one Physician Record relates directly to one User Record.
 
Reactor supports cascading saves.  This means that if you load a Physician Record and it's configure to have one User Record that saving the Physician will save the User.  However, because the Phsyician's PK value is based on the value of the User Record the User Record must be saved first.  To automate this process you can set the sharedKey attribute on the Physician (or Developer) to true.  Reactor will automatically save the records correctly.  
 
Here's an example configuration:
 

<reactor>
 <objects>
   <object name="Physician" sharedKey="true">
     <hasOne name="User">
       <relate from="physicianId" to="userId" />
     </hasOne>
   </object>

   <object name="Developer" sharedKey="true">
     <hasOne name="User">
       <relate from="developerId" to="userId" />
     </hasOne>
   </object>

   <object name="User" />

 </objects>
</reactor>

 
This configuration will allow for the following code to work:

 

<!--- create the reactorFactory --->
<cfset Reactor = CreateObject("Component", "reactor.reactorFactory").init(expandPath("reactor.xml")) />

<!--- populate the physician --->
<cfset Physician = Reactor.createRecord("Physician") />
<cfset Physician.setLanguage("ColdFusion") />
<cfset Physician.setLikesCoffee(true) />
<cfset Physician.getUser().setUsername("dhughes") />
<cfset Physician.getUser().setPassword("example") />
<cfset Physician.getUser().setFirstName("Doug") />
<cfset Physician.getUser().setLastName("Hughes") />

<!--- save the physician --->
<cfset Physician.save() />

 
This example will save the User, get the userId and set that into the phsycianId before saving the physician.

Attributes

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.

sharedKey

No

This indicates if the primary key on this object is related to the primary on the related object.  When not provided this defaults to false.  

Child tags

Tag

Required

Description

relate

yes

Defines what fields that relate this object to the related object.

Example

<reactor>
 <objects>
   <object name="Customer">
     <hasOne  name="Address">
       <relate from="addressId" to="addressId" />
     </hasOne>
   </object>

   <object name="Address" />
 <objects>
</reactor>