So today I came across a problem that the fine folks on the reactor list server help me solve. I wanted to run a transaction on multiple object so that if any of them failed I could back out. Here is a quick example of what I was trying to do.

view plain print about
1<cftransaction action="BEGIN">
2
3    <cfset contactRecord = application.reactor.createRecord("contact")/>
4    <cfset contactRecord.setContactId(form.contactId)>
5    <cfset contactRecord.setFname(form.fname)>
6    <cfset contactRecord.setLname(form.lname)>
7    
8    <cfset contactRecord.validate() />
9    <cfset errorCollection = contactRecord._getErrorCollection() />
10    <cfset contactRecord.save()>
11    
12    <cfset userRecord = application.reactor.createRecord("user")/>
13    <cfset userRecord.setuserId(form.userId)>
14    <cfset userRecord.setUsername(form.username)>
15    <cfset userRecord.setPassword(form.password)>
16    
17    <cfset userRecord.validate() />
18    <cfset errorCollection = userRecord._getErrorCollection() />
19    <cfset contactRecord.save()>
20    
21    <cfif ErrorCollection.hasErrors()>
22        <cftransaction action="ROLLBACK"/>
23    <cfelse>    
24        <cfset contactRecord.save()>
25        <cftransaction action="COMMIT"/>
26        <cflocation URL="contacts.cfm" addtoken="false"/>
27    </cfif>
28    
29</cftransaction>

The problem with this code is that it was throwing a transaction nested exception error. You can not place cftransaction tags inside themselves. I couldnt figure out why that was until I dug into the abstractRecord.cfc and found this.

view plain print about
1<cffunction name="save" access="public" hint="I save the record." output="false" returntype="void">
2        <cfargument name="useTransaction" hint="I indicate if this save should be executed within a transaction." required="no" type="boolean" default="true" />
3        
4        <cfif arguments.useTransaction>
5            <cfset saveInTransaction() />
6        <cfelse>
7            <cfset executeSave() />
8        </cfif>
9        
10    </cffunction>    
11    
12    <!--- saveInTransaction --->
13    <cffunction name="saveInTransaction" access="private" hint="I save the record in a transaction." output="false" returntype="void">
14        <cftransaction>
15            <cfset executeSave() />
16        </cftransaction>
17    </cffunction>

It now made perfect sense why this was happening. If you would like to tell reactor not to execute a save in a transaction simply pass false when calling the save method, the default value for this is true.

view plain print about
1<cfset contactRecord.save(false)>