Reactor save() & transaction gotcha

Word Count: 311

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.

<cftransaction action="BEGIN">

   <cfset contactRecord = application.reactor.createRecord("contact")/>
   <cfset contactRecord.setContactId(form.contactId)>
   <cfset contactRecord.setFname(form.fname)>
   <cfset contactRecord.setLname(form.lname)>
   
   <cfset contactRecord.validate() />
   <cfset errorCollection = contactRecord._getErrorCollection() />
   <cfset contactRecord.save()>
   
   <cfset userRecord = application.reactor.createRecord("user")/>
   <cfset userRecord.setuserId(form.userId)>
   <cfset userRecord.setUsername(form.username)>
   <cfset userRecord.setPassword(form.password)>
   
   <cfset userRecord.validate() />
   <cfset errorCollection = userRecord._getErrorCollection() />
   <cfset contactRecord.save()>
   
   <cfif ErrorCollection.hasErrors()>
      <cftransaction action="ROLLBACK"/>
   <cfelse>   
      <cfset contactRecord.save()>
      <cftransaction action="COMMIT"/>
      <cflocation URL="contacts.cfm" addtoken="false"/>
   </cfif>
   
</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.

<cffunction name="save" access="public" hint="I save the record." output="false" returntype="void">
      <cfargument name="useTransaction" hint="I indicate if this save should be executed within a transaction." required="no" type="boolean" default="true" />
      
      <cfif arguments.useTransaction>
         <cfset saveInTransaction() />
      <cfelse>
         <cfset executeSave() />
      </cfif>
      
   </cffunction>   
   
   <!--- saveInTransaction --->
   <cffunction name="saveInTransaction" access="private" hint="I save the record in a transaction." output="false" returntype="void">
      <cftransaction>
         <cfset executeSave() />
      </cftransaction>
   </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.

<cfset contactRecord.save(false)>

Comments

#1 Posted By: software development uk Posted On: 10/8/09 9:02 AM
Nice post,

reactor list is the greatest.. thanks for the help..

Thanks for bringing this up


Post Your Comment

Leave this field empty







Show Captcha

If you subscribe, any new posts to this thread will be sent to your email address.

Copyright © 2007 Dan Vega | BlogCFC was created by Raymond Camden. This blog is running version 5.8.001.