Posted in ColdFusion | Posted on 06-22-2007 | 1,814 views
I was helping a user yesterday who ran into an odd problem. His CFC was using Application.DSN (which is another problem) and he kept getting an error that said Application.DSN didn't exist. He copied his line that defined Application.DSN and set it in the Request scope. When he updated the CFC to use the Request scope, it worked fine. What was the problem? Here is some code that simulates his Application.cfm. See if you can spot it before reading on....
2<cfset application.dsn = "goo">
3<cfset request.dsn = "goo">
4<cfapplication name="myapp">
5<cfset application.random = "Paris Hilton is my idol....">
6
7test.cfm:
8<cfdump var="#application#">
9<cfdump var="#request#">
If you run this test, you will clearly see that the Application scope only has one variable, random. The Request scope shows the DSN. So now you can see what he saw - that the Application scope was working incorrectly and the Request scope worked fine.
But... look again. Do you see his CFAPPLICATION tag? It is after his application.dsn line. ColdFusion had not "started" the Application yet. Therefore his DSN variable was actually added to the magical unnamed Application scope area. To see what I mean, simply add a dump before his CFAPPLICATION tag.
So two lessons from this:
1) First, always remember to put the CFAPPLICATION tag before any code that actually uses the Application scope.
2) Second, this is one more big reason to migrate to Application.cfc. If he had used onApplicationStart(), this would not/could not have happened.


I totally agree with you here. There is no need to be referencing application.dsn inside of your cfc. I wrote an article about avoiding global data in this case. http://www.danvega.org/blog/index.cfm/2007/2/19/Av... . The other thing wrong with that code is that Paris hilton should be nobody's Idol :-)
"Hello, Ray!"
I could write my CFC to do this:
return "Hello, " & session.name
And that works fine - but note the use of session.name. The CFC assumes that the session scope is enabled and that the name key stores my name. If I stop using the session scope or switch to a different key (or keys, maybe client.firstname and client.lastname), then my CFC suddenly stops working.
But if my CFC took an argument, name, and did this:
return "Hello, " & arguments.name
It now works no matter what scope my name is stored in.
What version of CF can you start to use app.cfc? MX7?
And Dan - in your example - you show that:
<cfargument name="dsn" type="string" required="true">
<cfset variables.dsn = arguments.dsn>
and then in the CFC query you use datasource="#variables.dsn#"
- - Which I understand how it works - but, why is that better? Because of memory use?? Isn't the idea to only set one variable once? (especially if it doesn't change?)
I thought the idea of "application." variables was that if it is "app" wide - you only have to set it once and then it's done. In your example - we would continually be setting that value for each CFC in the App... Which seems redundant to a fault. So - what am I missing? Future Flexibility?
I realize I'm digressing wildly from the point of this post, so feel free to stop me-- I'm just thinking out loud. I have a lot of Coldfusion 5 code that's in the process of migrating to MX, so this is basically a new problem to me. I've never had to worry about passing datasources into functions because in addition to no CFCs, CF5 doesn't have CFFUNCTION and therefore you can't run a query in a UDF. I'm used to setting application.dsn once and being able to assume that all of the code in the application can use it.
Having to include a DSN argument in every function you create sounds like a lot of work. Further, I would worry about consistency-- some functions would have the DSN first, some would have it last. Would it make sense to have a singleton datasource object that is inherited by other objects in the app? Is there a convention for how this problem is handled in Coldfusion OO code?
<cffunction name="init" returntype="any" output="false">
<cfargument name="dsn" required="true">
<cfscript>
this.dsn = arguments.dsn;
</cfscript>
<cfreturn this />
</cffunction>
and then in your code you just call the init function.
<cfscript>
products = createobject("component","cfc.name").init(application.dsn);
<cfscript>
and within the CFC you would use this.dsn for datasource name.
CFCs are the way to go IMHO.
Encapsulation sometimes DOES mean more work. But we code for stronger code, not for 'getting it done as fast as possible.' ;)
As for having a consident "place" for DSN - don't forget you can always used named params:
foo = myfuncorcfc.function(name="ray", dsn="#application.dsn#", etc=foo)
simplico's answer works for me... thanks simplico!
[Add Comment] [Subscribe to Comments]