Model-Glue / Reactor Scaffolds : List screens and those linked descriptions
Published March 27th, 2008 in ColdFusion, Model-Glue MVC Framework, Reactor Framework, Software DevelopmentHere is the problem: Model-Glue scaffolds give you a nice skeleton to work with. My specific issue was with the list screens, which use a query object to populate the table in the view. If it were an iterator with records, then I would have no issue. However, Model Glue only gives the option of a query. This isn’t too bad for fairly denormalised data, but for heavily normalised tables, this represents a slight issue. If I were dealing with an iterator of reactor record objects, then I could use the getters for the linked tables and the getters for their linked tables, etc.
Here is a sample problem:
Table I am listing from: JobApplication
Links to tables: Job, Candidate
Job also links to Employer
JobApplication just holds state information about a job application. On the list page I need to display the Job Title (from Job), Candidate Name (from Candidate) and Company Name (from Employer via Job).
I did come up with a solution (though you should read UPDATE 2 for the best performing solution). What I wanted to avoid was having to go messing around with the ORMFactory that is Model Glue’s generic ORM factory for Reactor and / or Transfer. Here’s what I did…
1) I added a broadcast to ModelGlue.xml under the JobApplication.List event handler. The entire event handler now look like this:
<event -handler name="JobApplication.list" access="public">
<broadcasts>
<message name="ModelGlue.genericList">
<argument name="criteria" value="" />
<argument name="object" value="JobApplication" />
<argument name="queryName" value="JobApplicationQuery" />
</message>
<message name="ModelGlue.genericRead">
<argument name="criteria" value="JobId,CandidateId" />
<argument name="object" value="JobApplication" />
<argument name="recordName" value="JobApplicationRecord" />
</message>
</broadcasts>
<views>
<view name="body" template="dspJobApplicationList.cfm" append="true">
<value name="xe.view" value="JobApplication.view" overwrite="true" />
<value name="xe.delete" value="JobApplication.delete" overwrite="true" />
<value name="xe.edit" value="JobApplication.edit" overwrite="true" />
</view>
</views>
<results>
<result do="view.template" />
</results>
</event>
I added the genericRead broadcast for JobApplicationRecord. My understanding is that when the list page event fires, the genericRead will be broadcast and picked up by the model glue controller and because I have no JobApplicationId criteria in any variable out there, the JobApplicationRecord in the viewstate will just be an empty, unpopulated object.
2) In my view I get the empty JobApplicationRecord object from the viewstate and do a simple init() and load() with the key information from the query loop:
<cfoutput query="JobApplicationQuery">
<cfset keyString = "&JobId=#urlEncodedFormat(JobApplicationQuery.JobId)#&CandidateId=#urlEncodedFormat(JobApplicationQuery.CandidateId)#" />
<tr <cfif JobApplicationQuery.currentRow mod 2 eq 0>class="even">
<cfset JobApplicationRecord = viewState.GetValue("JobApplicationRecord").init(JobId=JobApplicationQuery.JobId,CandidateId=JobApplicationQuery.CandidateId).load() />
<td>
<cfif StructKeyExists(JobApplicationRecord,"getJob")>
<cfset JobRecord = JobApplicationRecord.getJob() />
#JobRecord.getJobTitle()#
</cfif>
/
<cfif StructKeyExists(JobRecord,"getEmployer")>
<cfset EmployerRecord = JobRecord.getEmployer() />
#EmployerRecord.getCompanyName()#
</cfif>
</td>
<td>
<cfif StructKeyExists(JobApplicationRecord,"getCandidate")>
<cfset CandidateRecord = JobApplicationRecord.getCandidate() />
#CandidateRecord.getLastName()#, #CandidateRecord.getFirstName()# #CandidateRecord.getMiddleName()#
</cfif>
</td>
<td>#dateFormat(ApplicationDate, viewState.GetValue("genConfig").dateformat)#</td>
<td>#htmlEditFormat(RecordStatus)#</td>
<td>#dateFormat(DateTimeModified, viewState.GetValue("genConfig").dateformat)#</td>
<td>
Edit
Delete
</td>
</tr>
</cfoutput>
Of course, JobApplicationQuery comes into the viewstate pre-populated. Getting the job record is straightforward (JobApplicationRecord.getJob()) and then so is getting the employer record associated with that job (JobRecord.getEmployer())
And that’s it!
Now, I’m no Model Glue or Reactor expert. In fact it’s only days that I have been working with them. I can’t put my hand on my heart and say that getting the empty record object from the broadcasted genericRead is best practice. If there is a better way to do it, I would like to know about and understand why it is better. My approach looks elegant and uses the minimum of code, relying a little on XML config. Maybe someone will find it useful.
UPDATE:
I had a look at the performance cost of have this type of genericRead broadcast and with Reactor running in production mode, the time taken was almost insignificant, e.g. typically 24ms when running it on a vmware guest operating system, so a production system will probably do it in half that. Given that there would be a cost in using the generic ORM factory to create the object anyway, then I don’t see any performance disadvantage in using this approach.
Now, that still leaves the performance of each call to load JobApplicationRecord, which is done on every loop through the JobQuery. It would have been much more efficient to get the job title, company name, and candidate name from the query, if it contained this information. But, that doesn’t come out of the box, so to speak, with the scaffolding and at this stage is beyond my know-how. For now I will live with the performance cost and continue to look at better ways of doing it.
UPDATE 2 (17-April-2008):
I found an alternative (and better) solution to this problem using a parameter I knew nothing about until I found it quite by accident:
http://blog.tech-cats.com/2008/01/using-generic-lists-and-sql-server.html
In the example I used, a stored procedure could be written that would join the JobApplication with Job (and associated Employer) and Candidate to get descriptions. Problem solved. I liked my code solution, but it’s better to encapsulate this into the database, perhaps even using a view to represent all the data associated with job applications. There is also the added performance benefit of making one single call to the database when the genericList broadcast message is handled, rather than expensive calls each time we loop through the JobApplication query. Thanks go to Boyan Kostadinov.
Technorati Tags: Model-Glue, modelglue, model glue, reactor, coldfusion, orm framework
No Responses to “Model-Glue / Reactor Scaffolds : List screens and those linked descriptions”
Please Wait
Leave a Reply