Object Oriented Programming (OOP) Question Regarding Data Access Objects (DAO)
I just finished reading a book on introducing Object Oriented Programming (OOP) in ColdFusion. I found the book to be very enlightening on many levels however I was left with some questions and there didn't seem to be anywhere to go after the book to learn more advanced topics or to seek clarification or more information.
I may be creating a few questions on this forum over the next few days/weeks with OOP related subjects and ColdFusion that I would love your feedback and opinions on - especially from people that have experience working with OOP.
This question pertains to Data Access Objects (DAO) and best practices or recommendations for using them in a ColdFusion application. I'll be using a generic "User DAO" as an example.
Historically whenever I've created a DAO method that updates a database table within a CFC I've always included a <cfargument> for every single column that can be updated in the database. Then within my method I check for the existence of an argument and if passed, I update that column. The end result is an update method which only updates database columns that were passed as arguments. This has always made sense to me for example if the user wants to update their password you can simply update that one field.
Here's an example method to show what I mean:
<cffunction name="updateUser">
<cfargument name="usersID" type="numeric" required="yes" />
<cfargument name="firstName" type="string" required="no" />
<cfargument name="lastName" type="string" required="no" />
<cfargument name="emailAddress" type="string" required="no" />
<cfargument name="passwordHash" type="string" required="no" />
<!--- update the database --->
<cfquery datasource="#application.dsn#">
UPDATE Users
SET DateModified = #createODBCDateTime(now())#
<!--- go through each column, check to see if an argument was passed and if so, update the column --->
<cfif structKeyExists(arguments, "firstName")>
, firstName = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.firstName#" />
</cfif>
<cfif structKeyExists(arguments, "lastName")>
, lastName = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.lastName#" />
</cfif>
<cfif structKeyExists(arguments, "emailAddress")>
, emailAddress= <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.emailAddress#" />
</cfif>
<cfif structKeyExists(arguments, "passwordHash")>
, passwordHash = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.passwordHash#" />
</cfif>
WHERE UsersID = <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.usersID#" />
</cfquery>
<cfreturn true />
</cffunction>
In the book, the author shows a similar method however instead of passing individual arguments, he suggests passing a single bean object to the method and then updating the data. Here's an example:
<!--- UPDATE --->
<cffunction name="updateUser">
<cfargument name="userBean" type="any" required="yes" />
<!--- update the database --->
<cfquery datasource="#application.dsn#">
UPDATE Users
SET DateModified = #createODBCDateTime(now())#
, firstName = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.userBean.getFirstName()#" />
, lastName = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.userBean.getLastName()#" />
, emailAddress= <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.userBean.getemailAddress()#" />
, passwordHash = <cfqueryparam cfsqltype="cf_sql_varchar" value="#arguments.userBean.getPasswordHash()#" />
WHERE UsersID = <cfqueryparam cfsqltype="cf_sql_integer" value="#arguments.userBean.getUsersID()#" />
</cfquery>
<cfreturn true />
</cffunction>
While this makes sense because you can pass a single object as an argument instead of a bunch of arguments it doesn't make sense to me to update database columns for data that hasn't necessarily changed or that the calling service object wasn't designed to update (again like updating a password).
I've also seen discussion online for other languages where people seem to discourage writing methods with a lot of arguments but I haven't been able to figure out why. My only guess is because many other languages don't allow for passing named argument collections (like CFML does) so you'd have to be very careful about the order you submit your arguments.
I'd love your opinion on whether creating a DAO object method that accepts a single bean object is better than a method requiring only the arguments that actually need updating.
