Objects Can Beat Recordsets for Display
In the old days (for me, about six months ago!) we all wrote queries and used cfoutput to display the results. These days we often use beans loaded by a DAO for single records instead. Why? They are a little more trouble, but even for data you only plan to display, encapsulating the getters allows you to vary your implementation (how a particular attribute is calculated or what internal properties it depends upon) without breaking your interface (you still just call the getter) . . .
In many cases this really doesn’t matter, so for many applications there is a story to using a recordset for all display data (single record or collection). It is easy, it performs well, and it avoids unnecessary complexity.
However, if you have an application where you want to use a bean for single record display purposes, why wouldn’t you just use a collection of beans for displaying a collection of records? What, it is important to encapsulate one record, but if you’ve got a bunch of them you’re just going to let it all hang out?!!! It makes no sense (actually, it could make sense if the only fields you needed to encapsulate are ones that are never shown on your master/list pages, but to me that is a heck of a fragile way of building an application!).
So, let’s take my prototypical use case for getters. I have a user table with FirstName, LastName and DateofBirth properties, but I want to be able to display FullName, FirstName, LastName, Age and/or DateofBirth. Also, any of those fields may be used in an individual record or in a master/list view. This may be too simple a case to be worthy of the discussion, but I hope it is a good real world example of the type of problem we are looking at.
So, I want to display Age on a view. No problem, I get my bean and call User.getAge() to display the age. Inside the bean there is probably a custom getter operating on the DateofBirth field, who knows . . . who cares?! But now I want to display Age in on a list page. What to do?
One solution would be to duplicate the code – hopefully in the model (what should a display page know about calculating ages?!), but I really don’t want to repeat myself unless I have to (lets stay DRY). I could push back the creation of Age and FullName to the database, but I don’t really want my business rules in the database and there are some calculations that can’t easily be performed in SQL (especially if you have to worry about cross db considerations).
What I’m suggesting is that we already have the code – right there in the bean. Many java developers would just create a collection of beans, iterate through them and be done with it, but component instantiation is expensive in CF, so it would be nice to have a higher performance way of obtaining the same results.
Luckily there is one. Just load the query into a bean, add the ability for the bean to iterate through the query (such as with first(), next() and IsLast() methods) and return that bean to all of your display code. Whether you have 1 record or 0..n records you pass the same object and can use the same code (getters and/or setters). Stick all of this into a baseBean that all of your beans inherit and it is extremely easy to work with. I’ll post sample code early next week.
This also means that if you have a lot of dynamic display code that can be used to display 1 or 0..n records, you don’t have to have two versions (one with #FirstName# and the other with #myUser.getFirstName()#). This will probably make more sense as I get a chance to blog about how I’m doing displays and a bunch of other things, but for now:
If you need getters for your object views (if you are displaying calculated attributes or just want to encapsulate accessing of your data)
AND
If you want to display calculated attributes on both list and view pages
THEN
Consider using a bean with a built in iterator to get the benefits of encapsulating data access without the performance costs of instantiating a collection of objects or the maintenance costs of duplicated code.
As with all approaches, your mileage will vary. This is not the "one true way" to handle data you primarily want to display – both in views and lists. It is an approach to consider.



This approach can also be used to decouple the names of object attributes from any underlying database field names. Usually a gateway will return a straight query, so if your field name changes, your display code will have to change. While you could wrap all of your queries with AS's or could add a routine to handle aliases in your gateway, it seems more pragmatic (in the spirit of Dougs recent post - http://www.doughughes.net/index.cfm?event=viewEntr... to use the same aliasing code for single records and for recordsets.
Does anyone have thoughts on this issue?
I agree 100% which is why my gateway (actually, I use a DAO for both single and multiple record actions, but I digress) returns ONLY A SINGLE OBJECT.
You want to view one user? You get one user object.
You want to list 20 articles? You get back ONE article object containing data for all 20
You and to list 300 products? You get back ONE product object containing data for all 300
It gives you all of the benefits of getters and setters and you just load it up using a loadQuery() method so it's easy to add to current recordset based code, and to display a list of 20 articles you just do something like:
Display.Article.First()
cfloop condition="NOT #Display.Data.Product.isLast()#"
- display record here
Display.Article.next()
/cfloop
I find instantiating the single object has a negligable impact on performance.
Best Wishes,
Peter
Just a little more on optimization. When I have large recordsets I typically use a stored procedure for paging and just return the records required for a view, loading them into my iterating business object. If you wanted to store your 50,000 records in memory (not sure I'd go there, but if that is a faster approach) I would NOT load 50,000 records into the object in application scope as the iteraor is not thread safe. Rather I'd instantiate an object per page request and load the 50 or 100 records into it per page view from whatever structure you stored the 50,000 records in. Make sense?
Best Wishes,
Peter
That sounds like a much better solution to me. Could I get a look at this code your talking about. I'm interested in knowing why it wouldn't be thread safe in application scope. Is it not a case of just 'var' ing everything inside your CFC's?
Will write a new post tonight or in the morning with all of the sample code. Reason the bean isn't thread safe is that it is designed as a business bean (stateful) not a singleton (stateless). If three pages called the Next() method, the iterator would go three steps forward (one for each method call).
Only point I'm making with this is that the actual iterating business bean should be request scoped. Doesn't mean you can't load it from an app scoped data set rather than a db if you so desire.
Best Wishes,
Peter
Just wondering if you know when (and where) you will be posting the sample code you mentioned. I am keen to take a look at it.