Paul –

 

First off, it looks like your method names are backwards.  IE save has transactions while vs. saveWithTransaction does not.

 

I do like your suggestion.  I’ve been thinking about transactions for this very reason. 

 

I see a few options which I will freeform below:

 

1)       Transactions are the developers problem.  In this case I’d remove it from the framework altogether and leave it in the developers court to handle.

 

2)       Transactions are moved into the record and can be optionally disabled.  This is essentially what you’ve suggested.  I’d do the same thing (I think) for loads and deletes too.  However, rather than having two methods I’d probably have one method that you could pass an argument into.  IE:

 

<cffunction name="save" returntype="void" access="public">

<cfargument name=”useTransactions” default=”true />

            <cfif arguments.useTransactions>

                  <cftransaction>

                        <cfset beforeSave()>

 

<cfset _getDAO().save(...)>

 

                        <cfset afterSave()>

      </cftransaction>

<cfelse>

                        <cfset beforeSave()>

 

<cfset _getDAO().save(...)>

 

                        <cfset afterSave()>

</cfif>

</cffunction>

 

That said, I’m not sure how that’d word with saves/deletes very cleanly, but we’ll see.

 

Any other thoughts?

 

Doug

 


From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Paul Kenney
Sent: Tuesday, April 25, 2006 2:51 AM
To: [email protected]
Subject: [Reactor For CF] Transactions...

 

A while ago, I tried wrapping a call to a XyzRecord's save() method inside a <cftransaction> tag, and discovered that transactions already a part of the framework. After looking at how the transactions are being used, I found that they are placed inside the DAOs in the save() method. A long time ago I learned that a transaction is really a "business-level" concept that encompass all the tables/records needed to persist a single object and all its dependencies. With that in mind, it makes more sense for me to have transactions live in the XyzRecord object, outside of the DAOs used by the XyzRecord object.

For instance, consider a Contact object with an address, a couple of phone numbers and two email addresses. As things stand now,  when I save a contact Record object, the Contact is saved, then the address, phone numbers, and email addresses, each with the id for the saved contact object. If save() is called on the address before the phone numbers or emails, and it fails (from a constraint violation), those phone numbers and emails are not saved. What is saved, though, is a contact record and if any changes were made to its dependent objects the database is now in a state that is inconsistent with the in-memory model.  This is caused by the fact that each object is saved in its own transaction, independent of the others, and the failure of one part (like the address) does not rollback the incomplete persistence of the contact.

What I was thinking might be possible is to have the Record object's save() method operate in two modes: one that creates a new transaction and another that works within an existing transaction. To accomodate these two modes, there would be two methods: save() and saveWithTransaction(). The save method would create a new transaction, and any dependent objects would be saved  using the saveWithTransaction() method.

<cffunction name="save" returntype="void" access="public">
   <cftransaction>
      <cfset beforeSave()>

      <cfset _getDAO().save(...)>

      <cfset afterSave()>
   </cftransaction>
</cffunction>

<cffunction name="saveWithTransaction" returntype="void" access="public">
   <cfset beforeSave()>

   <cfset _getDAO().save(...)>

   <cfset afterSave()>
</cffunction> 

<cffunction name="beforeSave" returntype="void" access="private">
   <cfloop ...>
      <cfset child.saveWithTransaction()>
   </cfloop>
</cffunction>

<cffunction name="afterSave" returntype="void" access="private">
   <cfloop ...>
      <cfset child.saveWithTransaction()>
   </cfloop>
</cffunction>


I'm not sure if this poses any difficulties with the existing way of doing things, or if I have missed something that renders this irrelevant.  Any thoughts, folks?

--
Paul Kenney
[EMAIL PROTECTED]
http://www.pjk.us -- Reactor for ColdFusion Mailing List -- [email protected] -- Archives at http://www.mail-archive.com/reactor%40doughughes.net/

-- Reactor for ColdFusion Mailing List -- [email protected] -- Archives at http://www.mail-archive.com/reactor%40doughughes.net/

Reply via email to