Learning ColdFusion 9: Application-Specific Data Sources

Posted July 13, 2009 at 10:27 AM by Ben Nadel

Tags: ColdFusion

As I stated in my blog post on ColdFusion 9 implicit struct and array usage, I think that it's sometimes the little feature upgrades that make the biggest difference in the long run. Another little feature in ColdFusion 9 that's going to make our lives a lot easier is the addition of application-specific data sources. While this application property is oddly missing from the beta documentation, if you've followed ColdFusion blogs, you've probably seen that in ColdFusion 9's Application.cfc, you can now define your query datasource as an attribute of the THIS scope:

  • <cfcomponent
  • output="false"
  • hint="I define application settings and event handlers.">
  •  
  • <!--- Define application settings. --->
  • <cfset this.name = hash( getCurrentTemplatePath() ) />
  •  
  • <!---
  • Define the data source to be used by all CFQuery tags
  • within this application. With this in place, you will not
  • need to define a Datasource attribute in and of your
  • CFQuery tags.
  • --->
  • <cfset this.datasource = "ben" />
  •  
  • <!--- Define page settings. --->
  • <cfsetting showdebugoutput="false" />
  •  
  • </cfcomponent>

Notice that Application.cfc now has a "this.datasource" property. With this defined, I no longer need to include a Datasource attribute in any of my CFQuery tags. To test this, I set up a simple index.cfm page that creates, populates, and then queries a table in the embedded Apache Derby database:

  • <!--- Drop the exist table. --->
  • <cfquery name="drop">
  • DROP TABLE girl
  • </cfquery>
  •  
  •  
  • <!---
  • Create the girls data table. The database I'm using
  • is an embeded Apach Derby database, hence the really
  • odd auto-increment syntax.
  • --->
  • <cfquery name="create">
  • CREATE TABLE girl
  • (
  • id int NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  • name varchar(30) NOT NULL,
  • hair varchar(30) NOT NULL,
  • PRIMARY KEY (id)
  • )
  • </cfquery>
  •  
  •  
  • <!--- Insert a records into the girl. --->
  • <cfquery name="insert">
  • INSERT INTO girl
  • (
  • name,
  • hair
  • ) VALUES (
  • <cfqueryparam value="Tricia" cfsqltype="cf_sql_varchar" />,
  • <cfqueryparam value="Brown" cfsqltype="cf_sql_varchar" />
  • )
  • </cfquery>
  •  
  •  
  • <!--- Query for girls. --->
  • <cfquery name="girls">
  • SELECT
  • id,
  • name,
  • hair
  • FROM
  • girl
  • </cfquery>
  •  
  •  
  • <!--- Output query records. --->
  • <cfdump
  • var="#girls#"
  • label="Girls (Derby)"
  • />

Notice that none of the CFQuery tags on the page define anything more than the Name attribute. The Datasource value which we would normally need now feeds of the application-specific Datasource property in the Application.cfc. When we run the above code, we get the following CFDump output:

 
 
 
 
 
 
ColdFusion 9 Application-Specific Datasource Property Allows Global Datasource Definition For Every CFQuery Tag. 
 
 
 

It works perfectly.

Just like most other application properties, this value can be changed on a per-page-request basis. Meaning, if you had this code in your Application.cfc:

  • <!--- Randomly set the app-specific data source. --->
  • <cfif (randRange( 1, 2 ) EQ 1)>
  • <cfset this.datasource = "ben" />
  • <cfelse>
  • <cfset this.datasource = "ben_bunk" />
  • </cfif>

... half of your page requests would error out. This, of course, is a silly example; but, if you needed to, you could easily extend your root Application.cfc and override the Datasource property. Keep in mind that this datasource property is a property of the application and not of any specific CFQuery tag. This means that if you create a CFC with one datasource and cache it, changing the datasource in the Application.cfc post-caching will still trickle down into the cached CFC, causing errors.

In the past, ColdFusion has been quite lenient for those of you who refuse to take up Application.CFC and abandon Application.CFM. Well, the "Datasource" property is not available on the CFApplication tag. If you want to use this (and other application-specific properties such as Mappings and CustomTagPaths) you need to be using Application.cfc. And, once you do, I think you'll find that this small upgrade will make life a whole lot nicer.


You Might Also Be Interested In:



Reader Comments

Jul 13, 2009 at 1:21 PM // reply »
4 Comments

And so is the cool ORM integration, which wont be available to Application.cfm users


Jul 13, 2009 at 1:25 PM // reply »
10,638 Comments

@Rahul,

Yeah... people seriously need to start using Application.cfc. It really just offers so many more advanced features!


Jul 13, 2009 at 7:34 PM // reply »
33 Comments

A nice feature, making CF just a little more convienient.


Jul 13, 2009 at 7:35 PM // reply »
33 Comments

Oh, and how do I get an avatar for my comments?? :)


Jul 13, 2009 at 8:00 PM // reply »
53 Comments

The change from application.cfm to application.cfc is going to be that much more easier with the extra functionality added to cfscript.

I come from a PHP background and believe that while markup has it's places (ie: cfquery), scripting is much easier to read and code.

If only we could drop in and out of cfscript while in the middle of loops and similar.

P.S: I have also been searching on how to change my avatar too.


Jul 14, 2009 at 12:26 AM // reply »
15 Comments

Hey Ben, Its Cool! What if we would like to go for extra attributes like username/password. can we also describe the same in the (this) scope in application.cfc to make it easier for a bit of security or not


Jul 14, 2009 at 12:30 AM // reply »
53 Comments

@Misty

Wouldn't you just set the other attributes like username and password for the datasource in CF administration?


Jul 14, 2009 at 12:57 AM // reply »
42 Comments

@Adam

Go to http://en.gravatar.com/ and sign up. A ton of sites out there use them. Then whenever you post to a site that uses them (and use the same e-mail), it will show up. :)


Jul 14, 2009 at 1:06 AM // reply »
33 Comments

Ah, got it. I had a Gravatar account, but under an older email address. This should work much better.


Jul 14, 2009 at 1:06 AM // reply »
33 Comments

Bah!!! Hmm, oh well.


Jul 18, 2009 at 4:03 PM // reply »
10,638 Comments

@Misty,

From what I can tell, there are no username / password attributes for the data source. Like Andrew is saying, you just need to set that up in the CFAdmin and refer only to the data source in the code.

As someone who is used to used passing username and password via the CFQuery tag traditionally, this will actually be a nice "forced" change :)


Don
May 6, 2010 at 4:47 PM // reply »
57 Comments

Yup, I wish it would let me do something like
<cfset this.datasource = "mydb,myusername,mypwd">

Why? Because some people want that added security of passing the username and password everytime. Of course then you get the people who want to encrypt the connection string.

BTW speaking of hash, what does hashing the current path into this.name do for you? Or do I need to go read other posts?


May 6, 2010 at 9:32 PM // reply »
10,638 Comments

@Don,

I know exactly what you are saying. My pre-CF9 applications all use datasource / username / password in the CFQuery tag for the flexibility. But, I think this is one of those situations where I am going to let the language decide for me. If they only allow me to put my datasource name, well then, I guess I need to start putting my username / password in the data source itself (in the CF Admin).

I know that's not the best line of logic; but gosh, I really do want to use the centralized datasource value!

As far as the hash() in name, I've actually had a number of people recently ask me about that. It helps to keep the application name unique without having to worry about copy-pasting files. Check this out:

http://www.bennadel.com/blog/1845-Making-Sure-Your-ColdFusion-Applications-Are-Uniquely-Named.htm

I know it might seem silly to not name applications. But, unless you use the name for something meaningful, this approach just gives me one less thing to worry about.


Sep 21, 2010 at 3:52 PM // reply »
57 Comments

I am also looking for a way to set the datasource username/password for the application as well...not so much to avoid having to set it in the administrator...but because on an Oracle database, the user is the schema name...you will often have many applications using the same database (and thus that can use the same datasource) but based on the login, will use a separate schema in that database. Having to set up datasources for every application is not really something we want to have to do.


Sep 21, 2010 at 4:51 PM // reply »
57 Comments

FYI - it does appear that the 9.01 allows you to set the datasource using a struct that includes the username/password. So yeah for that!


Sep 22, 2010 at 10:07 PM // reply »
10,638 Comments

@Mary Jo,

Oh cool - I was not aware that that was part of the updater. Man, I really need to get my hands on 9.0.1 and start playing with it. Thanks for the tip!


Nov 22, 2010 at 7:56 AM // reply »
2 Comments

My problem with the this.datasource is that the datasource name is hardcoded. Does anyone know how to make it dynamic?
I defined my default ds in coldspring and tried to set the this.datasource inside the onapplicationstart function ;) but it did not work.
Any ideas?


Dec 2, 2010 at 4:39 AM // reply »
1 Comments

Hi,
I'm new to all of this, so i used this.datasource like this :

  • <cffunction name="onApplicationStart">
  • <!--- Set the datasource --->
  • <cfset this.datasource="myDSN" />
  • </cffunction>

It works once and after it throws that :
The value of the attribute datasource, which is currently '', is invalid ???

please help to solve this prob.

Thanks,
Houssem


Dec 3, 2010 at 6:24 AM // reply »
2 Comments

@Houssem - I can relate to your problem since I also tried something like that. If you dump the this scope, you are actually going to see the value you assigned to the datasource but...


Dec 5, 2010 at 1:31 PM // reply »
10,638 Comments

@CFKelvin, @Houssem,

The properties of the THIS scope for per-application configuration have to be set in the pseudo constructor of the Application.cfc (the space outside the CFFunction tags). If you do it inside one of the event handlers (ex. onApplicationStart()), it's already too late.

@Houssem, I am not sure why it is giving you an error about the value as being invalid, though. I would just expect your CFQuery tags to fail. Although, in CF9, it might look at some internal property if you are not defining a datasource property on the CFQuery tag (which is not be set in time in the Application.cfc).

A lot of people have asked for this to be able to be set within an event handler. I personally don't understand this. Perhaps it's just because I don't use ColdSpring? I guess it forces you to think about datasources in a certain way.

You can always call one of the methods *from* the pseudo constructor. So, if you want to add logic for the per-server configuration, you can, at the least, encapsulate it within a method of the Application.cfc (if you don't want to clutter up the pseudo constructor).


Dec 6, 2010 at 3:16 PM // reply »
10 Comments

Ben,

Any ideas on why this will not work for CFSTOREDPROC tags? Seems like this is only for CFQUERY, but I cannot figure out why they'd only do it for that.


RR
Jul 19, 2011 at 1:16 PM // reply »
1 Comments

I get the same error even with this.datasource defined outside of all cffunction in application.cfc. Do you think this is a bug in cf9?

Thanks for your help --RR


Sep 7, 2011 at 4:18 PM // reply »
1 Comments

I just updated a project I'm working on to take advantage of this.datasource. Neat way to reduce code, but one limitation I discovered after doing a global find and replace is that CFInsert and CFUpdate don't recognize the new property. I had to put the old "application.dsn" variable back in on those tags. Shame, as imagine how compact they'd look written out like this...

<cfupdate tablename="account">

By the way, is there any way to get the value of the this.datasource property for general use? The "THIS" scope seems to not be available at the page level as doing <cfdump var="#this#"> throws an error. Any ideas?


Nov 3, 2011 at 11:45 AM // reply »
1 Comments

@Houssem,

I'm sure you figured this out by now, but if not:

I got that error "the value of the attribute datasource which is currently '' is invalid" when I had my application set to timeout immediately on each load for testing. In my application.cfc I had <cfset this.applicationTimeout = createTimeSpan( 0, 0, 0, 0 ) />.

Very foolish of me because when it came time for the queries to run the this.datasource application variable was gone because I timed it out!



Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Feb 3, 2012 at 10:49 PM
How I Got Node.js Running On A Linux Micro Instance Using Amazon EC2
Wow this was really helpful! Only thing I would add is you need to update your .bash_profile after you edit the secure_path. This is what I did: $ . ~/.bash_profile Otherwise, NPM won't be found. ... read »
Feb 3, 2012 at 10:14 PM
Pushing Base64-Encoded Images Over HTML5 WebSockets With Pusher And ColdFusion
@Ben, Just wanted to let you know that pusher are soon to start limiting sizes on messages. This was the detail that came through in the Feb dispatch: "However, we will soon be limiting the s ... read »
Feb 3, 2012 at 5:05 PM
Regular Expressions Make CSV Parsing In ColdFusion So Much Easier (And Faster)
I tried using your RegEx in my C# program, but it was matching an extra empty-string at the end and so I would end up with an extra field that doesn't exist, so I changed it to this: (^|,)("(?: ... read »
Feb 3, 2012 at 3:47 PM
ColdFusion Supports HTTP Verbs PUT And DELETE (As Well As GET And POST)
Josh Cyr posted this on Twitter just a little bit ago. Thought it was appropriate. http://stackoverflow.com/questions/1619152/how-to-create-rest-urls-without-verbs/1619677#1619677 ... read »
Feb 3, 2012 at 2:28 PM
Changing The Execution Context Of Your Self-Executing Function Blocks In JavaScript
@Michael, You definitely make a good point (and extra points for quoting movies - I love movies). When you use a return() statement to define the object's public API, it does provide a consistent a ... read »
Feb 3, 2012 at 2:04 PM
Changing The Execution Context Of Your Self-Executing Function Blocks In JavaScript
To quote Jurassic Park: "Just because you can doesn't mean you should". I completely, utterly disagree with the thought that this is more readable. Consider the current module pattern: if ... read »
Feb 3, 2012 at 1:10 PM
REST API Design Rulebook By Mark Masse
@Jordan, Yeah, WRML was created by Mark Masse (author of the book). I also found it to be a bit convoluted. I suppose it is intended to allow the Client to be able to programmaticaly respond to cha ... read »
Feb 3, 2012 at 1:08 PM
ColdFusion Supports HTTP Verbs PUT And DELETE (As Well As GET And POST)
@Jason, To be honest, I don't have good answers for that kinds of stuff. And, to the point, that is specifically why I *really* liked the REST API Design Rulebook by Mark Masse - he just cuts throu ... read »