In his Mach-II dev guide, Sean discusses a very similar organizational
scheme.

http://livedocs.macromedia.com/wtg/public/machiidevguide/models.html

The page has a bunch of Mach-II specific stuff at the top, but the last
section ("Database Access Objects") is of particular interest, and even
includes code samples from an app he wrote as the backend of one of the
Macromedia Central demo apps.

That whole article is a very good read, whether your doing Mach-II or not.
The specific examples are tied to the Mach-II framework, but the general
principles will hold no matter what you'd doing.  And it's even well
written, which is more that can be said of a lot of techical documents.

Cheers,
barneyb

> -----Original Message-----
> From: [EMAIL PROTECTED] 
> [mailto:[EMAIL PROTECTED] On Behalf Of Jim Davis
> Sent: Tuesday, December 09, 2003 6:02 PM
> To: [EMAIL PROTECTED]
> Subject: RE: [CFCDev] Wanted: OOP Best Practice for CFC's 
> with database interaction
> 
> I'm not sure how correct it is, but I tend to create two objects:
> 
> 1) A domain object - in your case "employee".  This contains all the
> information that could be needed by a single instance of the 
> domain object.
> 
> 2) An implementation object for working with the domain 
> object - for example
> "employeeCollection".  This collection object is designed to 
> hold multiple
> employee components.  It would contain methods like "getEmployees()",
> "getSortedBySalary()", etc.
> 
> Basically anything to do with lists of things would be 
> handled by specific
> collection objects.  I've found actually that my collection 
> objects have a
> tendency towards sameness - so I'm currently working on a 
> generic collection
> object that can be extended in domain specific ways.
> 
> Like I said - I'm new to this too and may be way off base on 
> this, but the
> method works for me.
> 
> Jim Davis
> 
> > -----Original Message-----
> > From: [EMAIL PROTECTED] 
> [mailto:[EMAIL PROTECTED] On Behalf
> > Of Kairoh!
> > Sent: Monday, December 08, 2003 7:43 AM
> > To: [EMAIL PROTECTED]
> > Subject: [CFCDev] Wanted: OOP Best Practice for CFC's with database
> > interaction
> > 
> > Hi everyone,
> > 
> >  I have build a simple employee CFC - shown below - that 
> interacts with a
> > database. This CFC uses a utilities CFC for handling 
> zero-length strings
> > and
> > preparing datefields for a database insert or update. The 
> CFC does the job
> > as expected. So far so good. But there are two questions 
> bothering me:
> > 1. From an OOP perspective an employee.cfc should not contain a
> > listEmployees method. How could I solve this? Sometimes you 
> need a list of
> > employees. How should this be done in a OOP best practice 
> example? Two
> > CFC's? A design pattern?
> > 2. I have the idea my implementation for accessing, 
> inserting and updating
> > could be done in a much cleaner fashion. Does anyone has a 
> suggestion how
> > to
> > improve it.
> > 
> > In summary, can anyone of you provide me with a best 
> practice example for
> > building an OOP-based CFC with integrated database 
> interaction that does
> > listings too. I have read Hal's book, but it does not 
> discuss database
> > access implementations. Ben's book has a nice example of 
> OOP and database
> > access but the example is based on a CFC/CFM combination. I 
> am planning to
> > use the CFC as part of a RIA application(CFC/SWF combination). All
> > suggestions, links, book titles, articles are welcome.
> > 
> > This is my first time on this list. (Don't shoot me, I have 
> searched the
> > archives but could not find the answer to my question).
> > 
> > Vinny
> > 
> > 
> > <cfcomponent displayname="Employee dataprocessing services" 
> hint="This
> > component provides employee information services">
> > 
> >   <cffunction name="listEmployees" access="remote" output="no"
> > returntype="query" displayname="List employees" 
> hint="Returns a list of
> > employees">
> > 
> >     <!--- Optional keyword argument --->
> > 
> >     <cfargument name="Keyword" type="string" required="false"
> > hint="Optional
> > search criteria; if not given, all employees are returned.">
> > 
> >     <!--- Get the employees information --->
> > 
> >     <cfset var q_EmployeesInfo="">
> > 
> >     <cfquery name="q_EmployeesInfo" 
> datasource="#APPLICATION.DataSource#">
> >             SELECT  Employees.EmployeeID,
> > Offices.OfficeName,Employees.FirstName
> > 
> >     FROM            Employees, Offices
> >     WHERE   Employees.Office = Offices.OfficeID
> > 
> >     <!--- If a keyword has been specified --->
> > 
> >     <cfif IsDefined("ARGUMENTS.Keyword")>
> >             AND             FirstName LIKE 
> '%#ARGUMENTS.Keyword#%' OR LastName
> > LIKE '%#ARGUMENTS.Keyword#%')
> >     </cfif>
> > 
> >             ORDER BY        Employees.LastName
> >     </cfquery>
> > 
> >     <!--- Finally, return the populated employee query. --->
> > 
> >     <cfreturn q_EmployeesInfo>
> >   </cffunction>
> > 
> >   <cffunction name="getEmployee" access="remote" output="no"
> > returntype="struct" displayname="Get employee information" 
> hint="Returns
> > detailed information about the specified employee">
> >     <cfargument name="EmployeeID" type="numeric" 
> required="true" hint="ID
> > specifying the particular employee to get">
> > 
> >     <!--- Get the employee information --->
> > 
> >     <cfset var q_EmployeeInfo="">
> > 
> >     <cfquery name="q_EmployeeInfo"
> > datasource="#APPLICATION.DataSource#">
> >             SELECT  *
> >             FROM            Employees, Offices
> >             WHERE   Employees.Office = Offices.OfficeID
> >                     AND             EmployeeID =
> > <cfqueryparamvalue="#ARGUMENTS.EmployeeID#" 
> cfsqltype="cf_sql_integer">
> >     </cfquery>
> > 
> >     <!--- If we do not find a record for the employee, the 
> object ID is
> > invalid. Throw an exception to notify the caller --->
> > 
> >     <cfif not q_EmployeeInfo.RecordCount>
> >             <cfthrow message="ERROR_UNKNOWN_USER">
> >     </cfif>
> > 
> >     <!--- Create a structure for the employee information. --->
> > 
> >     <cfset st_Employee = StructNew()>
> > 
> >     <!--- Populate the employee structure with employee 
> information.--->
> > 
> >     <cfset st_Employee.EmployeeID           = 
> q_EmployeeInfo.EmployeeID>
> >     <cfset st_Employee.OfficeID             = 
> q_EmployeeInfo.OfficeID>
> >     <cfset st_Employee.FirstName            = 
> q_EmployeeInfo.FirstName>
> >     <cfset st_Employee.Login                = q_EmployeeInfo.Login>
> >     <cfset st_Employee.Password             = 
> q_EmployeeInfo.Password>
> >     <cfset st_Employee.LastName             = 
> q_EmployeeInfo.LastName>
> >     <cfset st_Employee.BirthDate            = 
> q_EmployeeInfo.BirthDate>
> >     <cfset st_Employee.Email                = q_EmployeeInfo.Email>
> >     <cfset st_Employee.Remarks              = 
> q_EmployeeInfo.Remarks>
> >     <cfset st_Employee.Picture              = 
> q_EmployeeInfo.Picture>
> > 
> >     <!--- Finally, return the populated employee structure. --->
> > 
> >     <cfreturn st_Employee>
> >   </cffunction>
> > 
> >   <cffunction name="createEmployee" access="remote" output="no"
> > returntype="struct" displayname="Insert new employee" 
> hint="Inserts a new
> > employee in the system">
> >     <cfargument name="Office" type="numeric" 
> required="false" default=""
> > hint="The employee's office">
> >     <cfargument name="Login" type="string" required="true" hint="The
> > user's login">
> >     <cfargument name="Password" type="string" 
> required="true" hint="The
> > user's password">
> >     <cfargument name="LastName" type="string" required="false"
> > default="" hint="The user's last name">
> >     <cfargument name="BirthDate" type="date" 
> required="false" default=""
> > hint="The user's birthdate">
> >     <cfargument name="Email" type="string" required="false" 
> default=""
> > hint="The user's email">
> >     <cfargument name="Remarks" type="string" 
> required="false" default=""
> > hint="Remarks concerning the user">
> >     <cfargument name="Picture" type="string" 
> required="false" default=""
> > hint="The user's photo">
> > 
> >     <!--- Create a structure for the employee information. --->
> > 
> >     <cfset st_Employee = StructNew()>
> > 
> >     <cfset st_Employee.Login = " ">
> > 
> >     <!--- Before we add the employee, we need to make sure that the
> > employee's login does not already exist. If the employee 
> does exist, we'll
> > throw an exception. --->
> > 
> >     <cfif IsDefined("ARGUMENTS.Login")>
> >             <cfinvoke component="common" method="prepareTextField"
> > returnvariable="st_Employee.Login">
> >                     <cfinvokeargument name="TextField"
> > value="#ARGUMENTS.Login#">
> >             </cfinvoke>
> >     </cfif>
> > 
> >     <cfquery name="EmployeeCheck" 
> datasource="#APPLICATION.DataSource#">
> >              SELECT         *
> >              FROM   Employees
> >              WHERE  Login = <cfqueryparam 
> value="#st_Employee.Login#"
> > cfsqltype="cf_sql_varchar">
> >     </cfquery>
> > 
> >     <cfif EmployeeCheck.RecordCount>
> >             <cfthrow message="ERROR_USER_EXISTS">
> >     </cfif>
> > 
> >     <cftransaction action="begin"/>
> > 
> >     <cfset st_Employee.Office = " ">
> >     <cfset st_Employee.Login = " ">
> >     <cfset st_Employee.Password = " ">
> >     <cfset st_Employee.LastName = " ">
> >     <cfset st_Employee.BirthDate = " ">
> >     <cfset st_Employee.Email = " ">
> >     <cfset st_Employee.Remarks = " ">
> >     <cfset st_Employee.Picture = " ">
> > 
> >     <!--- Add the information from the arguments if they exist. --->
> > 
> >     <cfif IsDefined("ARGUMENTS.Office")>
> >             <cfinvoke component="common" method="prepareTextField"
> > returnvariable="st_Employee.Office">
> >                     <cfinvokeargument name="TextField"
> > value="#ARGUMENTS.Office#">
> >             </cfinvoke>
> >     </cfif>
> > 
> >     <cfif IsDefined("ARGUMENTS.Login")>
> >             <cfinvoke component="common" method="prepareTextField"
> > returnvariable="st_Employee.login">
> >                     <cfinvokeargument name="TextField"
> > value="#ARGUMENTS.Login#">
> >             </cfinvoke>
> >     </cfif>
> > 
> >     <cfif IsDefined("ARGUMENTS.Password")>
> >             <cfinvoke component="common" method="prepareTextField"
> > returnvariable="st_Employee.password">
> >                     <cfinvokeargument name="TextField"
> > value="#ARGUMENTS.Password#">
> >             </cfinvoke>
> >     </cfif>
> > 
> >     <cfif IsDefined("ARGUMENTS.LastName")>
> >             <cfinvoke component="common" method="prepareTextField"
> > returnvariable="st_Employee.LastName">
> >                     <cfinvokeargument name="TextField"
> > value="#ARGUMENTS.LastName#">
> >             </cfinvoke>
> >     </cfif>
> > 
> >     <cfif IsDefined("ARGUMENTS.BirthDate")>
> >             <cfinvoke component="common" method="prepareDateField"
> > returnvariable="st_Employee.BirthDate">
> >                     <cfinvokeargument name="DateString"
> > value="#ARGUMENTS.BirthDate#">
> >             </cfinvoke>
> >     </cfif>
> > 
> >     <cfif IsDefined("ARGUMENTS.Email")>
> >             <cfinvoke component="common" method="prepareTextField"
> > returnvariable="st_Employee.email">
> >                     <cfinvokeargument name="TextField"
> > value="#ARGUMENTS.Email#">
> >             </cfinvoke>
> >     </cfif>
> > 
> >     <cfif IsDefined("ARGUMENTS.Remarks")>
> >             <cfinvoke component="common" method="prepareTextField"
> > returnvariable="st_Employee.Remarks">
> >                     <cfinvokeargument name="TextField"
> > value="#ARGUMENTS.Remarks#">
> >             </cfinvoke>
> >     </cfif>
> > 
> >     <cfif IsDefined("ARGUMENTS.Picture")>
> >             <cfinvoke component="common" method="prepareTextField"
> > returnvariable="st_Employee.Picture">
> >                     <cfinvokeargument name="TextField"
> > value="#ARGUMENTS.Picture#">
> >             </cfinvoke>
> >     </cfif>
> > 
> >     <!--- Insert a employee info record into the database. --->
> > 
> >     <cfquery datasource="#APPLICATION.DataSource#">
> >              INSERT INTO    Employees (Office,
> >                                     Login,
> >                                     Password,
> >                                     LastName,
> >                                     BirthDate,
> >                                     Email,
> >                                     Remarks,
> >                                     Picture)
> >              VALUES         (<cfqueryparam 
> value="#st_Employee.Office#"
> > cfsqltype="cf_sql_integer">,
> >                                     <cfqueryparam
> > value="#st_Employee.Login#" cfsqltype="cf_sql_varchar">,
> >                                     <cfqueryparam
> > value="#st_Employee.Password#" cfsqltype="cf_sql_varchar">,
> >                                     <cfqueryparam
> > value="#st_Employee.LastName#" cfsqltype="cf_sql_varchar">,
> >                                     <cfqueryparam
> > value="#st_Employee.BirthDate#" cfsqltype="cf_sql_date">,
> >                                     <cfqueryparam
> > value="#st_Employee.Email#" cfsqltype="cf_sql_varchar">,
> >                                     <cfqueryparam
> > value="#st_Employee.Remarks#" cfsqltype="cf_sql_varchar">,
> >                                     <cfqueryparam
> > value="#st_Employee.Picture#" cfsqltype="cf_sql_varchar">)
> >     </cfquery>
> > 
> >     <!--- Commit the database changes. --->
> > 
> >     <cftransaction action="commit"/>
> > 
> >     <!--- Get the new ID. --->
> > 
> >     <cfquery name="q_returnQuery" 
> datasource="#APPLICATION.DataSource#">
> >              SELECT         @@identity
> >              AS                     newId
> >     </cfquery>
> > 
> >     <!--- Finally, return the new ID. --->
> > 
> >     <cfreturn getEmployee(q_returnQuery.newId)>
> >   </cffunction>
> > 
> >   <cffunction name="editEmployee" access="remote" output="no"
> > returntype="struct" displayname="Update employee information"
> > hint="Updates
> > employee information in the system">
> >     <cfargument name="EmployeeID" type="numeric" required="true"
> > hint="The unique object ID for the user">
> >     <cfargument name="Office" type="numeric" 
> required="false" hint="The
> > employee's office">
> >     <cfargument name="Login" type="string" required="true" hint="The
> > user's login">
> >     <cfargument name="Password" type="string" 
> required="true" hint="The
> > user's password">
> >     <cfargument name="LastName" type="string" 
> required="false" hint="The
> > user's last name">
> >     <cfargument name="BirthDate" type="date" 
> required="false" hint="The
> > user's birthdate">
> >     <cfargument name="Email" type="string" required="false" 
> hint="The
> > user's email">
> >     <cfargument name="Remarks" type="string" required="false"
> > hint="Remarks concerning the user">
> >     <cfargument name="Picture" type="string" 
> required="false" hint="The
> > user's photo">
> > 
> >     <!--- Create a structure for the employee's information. --->
> > 
> >     <cfset st_Employee = StructNew()>
> > 
> >     <cfset st_Employee.EmployeeID = ARGUMENTS.EmployeeID>
> > 
> >     <!--- Prepare the user info text fields for updating 
> the database
> > --->
> > 
> >             <cfinvoke component="common" method="prepareTextField"
> > returnvariable="st_Employee.Office">
> >                     <cfinvokeargument name="TextField"
> > value="#ARGUMENTS.Office#">
> >             </cfinvoke>
> > 
> >             <cfinvoke component="common" method="prepareTextField"
> > returnvariable="st_Employee.Login">
> >                     <cfinvokeargument name="TextField"
> > value="#ARGUMENTS.Login#">
> >             </cfinvoke>
> > 
> >             <cfinvoke component="common" method="prepareTextField"
> > returnvariable="st_Employee.Password">
> >                     <cfinvokeargument name="TextField"
> > value="#ARGUMENTS.Password#">
> >             </cfinvoke>
> > 
> >             <cfinvoke component="common" method="prepareTextField"
> > returnvariable="st_Employee.LastName">
> >                     <cfinvokeargument name="TextField"
> > value="#ARGUMENTS.LastName#">
> >             </cfinvoke>
> > 
> >             <cfinvoke component="common" method="prepareDateField"
> > returnvariable="st_Employee.BirthDate">
> >                     <cfinvokeargument name="DateString"
> > value="#ARGUMENTS.BirthDate#">
> >             </cfinvoke>
> > 
> >             <cfinvoke component="common" method="prepareTextField"
> > returnvariable="st_Employee.Email">
> >                     <cfinvokeargument name="TextField"
> > value="#ARGUMENTS.Email#">
> >             </cfinvoke>
> > 
> >             <cfinvoke component="common" method="prepareTextField"
> > returnvariable="st_Employee.Remarks">
> >                     <cfinvokeargument name="TextField"
> > value="#ARGUMENTS.Remarks#">
> >             </cfinvoke>
> > 
> >             <cfinvoke component="common" method="prepareTextField"
> > returnvariable="st_Employee.Picture">
> >                     <cfinvokeargument name="TextField"
> > value="#ARGUMENTS.Picture#">
> >             </cfinvoke>
> > 
> >     <!--- Update the employee's info --->
> > 
> >     <cftransaction action="begin"/>
> > 
> >     <cfquery datasource="#APPLICATION.DataSource#">
> >             UPDATE          Employees
> >             SET                     Office = <cfqueryparam
> > value="#st_Employee.Office#" cfsqltype="cf_sql_integer">,
> >                                     Login = <cfqueryparam
> > value="#st_Employee.Login#" cfsqltype="cf_sql_varchar">,
> >                                     Password = <cfqueryparam
> > value="#st_Employee.Password#" cfsqltype="cf_sql_varchar">,
> >                                     LastName = <cfqueryparam
> > value="#st_Employee.LastName#" cfsqltype="cf_sql_varchar">,
> >                                     BirthDate = <cfqueryparam
> > value="#st_Employee.BirthDate#" cfsqltype="cf_sql_date">,
> >                                     Email = <cfqueryparam
> > value="#st_Employee.Email#" cfsqltype="cf_sql_varchar">,
> >                                     Remarks = <cfqueryparam
> > value="#st_Employee.Remarks#" cfsqltype="cf_sql_varchar">,
> >                                     Picture = <cfqueryparam
> > value="#st_Employee.Picture#" cfsqltype="cf_sql_varchar">
> >             WHERE           EmployeeID = #st_Employee.EmployeeID#
> >     </cfquery>
> > 
> >     <!--- Commit the database changes. --->
> > 
> >     <cftransaction action="commit"/>
> > 
> >     <!--- Finally, return the userdata. --->
> > 
> >     <cfreturn getEmployee(st_Employee.EmployeeID)>
> >   </cffunction>
> > 
> >   <cffunction name="deleteEmployee" access="remote" output="no"
> > returntype="numeric" displayname="Delete employee information"
> > hint="Deletes
> > all information for the specified employee">
> >     <cfargument name="EmployeeID" type="numeric"  required="true"
> > hint="Unique object ID specifying the particular employee 
> to delete">
> > 
> >     <cftransaction action="begin"/>
> > 
> >     <!--- Delete the item from tbEmployees --->
> > 
> >     <cfquery datasource="#APPLICATION.DataSource#">
> >             DELETE FROM     Employees
> >     WHERE           EmployeeID = #ARGUMENTS.EmployeeID#
> >     </cfquery>
> > 
> >     <!--- Commit the database changes. --->
> > 
> >     <cftransaction action="commit"/>
> > 
> >     <!--- Finally, return the deleted employee. --->
> > 
> >     <cfreturn ARGUMENTS.EmployeeID>
> >   </cffunction>
> > </cfcomponent>
> > 
> > 
> > ----------------------------------------------------------
> > You are subscribed to cfcdev. To unsubscribe, send an email
> > to [EMAIL PROTECTED] with the words 'unsubscribe cfcdev'
> > in the message of the email.
> > 
> > CFCDev is run by CFCZone (www.cfczone.org) and supported
> > by Mindtool, Corporation (www.mindtool.com).
> > 
> > An archive of the CFCDev list is available at www.mail-
> > archive.com/[EMAIL PROTECTED]
> 
> 
> ----------------------------------------------------------
> You are subscribed to cfcdev. To unsubscribe, send an email
> to [EMAIL PROTECTED] with the words 'unsubscribe cfcdev' 
> in the message of the email.
> 
> CFCDev is run by CFCZone (www.cfczone.org) and supported
> by Mindtool, Corporation (www.mindtool.com).
> 
> An archive of the CFCDev list is available at 
> www.mail-archive.com/[EMAIL PROTECTED]
> 

----------------------------------------------------------
You are subscribed to cfcdev. To unsubscribe, send an email
to [EMAIL PROTECTED] with the words 'unsubscribe cfcdev' 
in the message of the email.

CFCDev is run by CFCZone (www.cfczone.org) and supported
by Mindtool, Corporation (www.mindtool.com).

An archive of the CFCDev list is available at www.mail-archive.com/[EMAIL PROTECTED]

Reply via email to