In our Portal application.cfc, we are defining (setting up) our DSN connections like so:
<cfset this.datasource = "DSN1"> (Main DB)
<cfset this.datasource_1 = "DSN2"> (2nd DB)
<cfset this.datasource_2 = "DNS3"> (3rd DB)
These are in the tags. I have also moved then to the ‘OnApplicationStart’ function and cannot get it to work correctly.
This application.cfc if referenced in the main APP, that the other apps have access to (App2, etc…), my question is;
How do I reference the other datasources (this.datasource_2) in a query for the App2 application?
<cfquery name="queryname" datasource="**[What goes here]**"> For second datasource
The this.datasource DSN is always being referenced because there is no datasource listed in the cfquery tags.
Any help you can provide or links to send my way will be appreciated. Thanks in advance!
Try seeing additional application variables
<cfset application.datasource_1 = "DSN2"> (2nd DB)
<cfset application.datasource_2 = "DNS3"> (3rd DB)
My solution is to not use any variables at all and simply hard code the datasource names. In other words, for this:
<cfquery name="queryname" datasource="**[What goes here]**"> For second datasource
The answer is "DSN2".
In order for these datasources to be usable, they have to be defined on the server and you have to know their names. If you assign them to some sort of global variable, then you would have to know the name of that variable. I see no value to using global variables in this situation.
For DSN1, there are pros and cons to using a global variable. The advantage of a variable is that you don't need a datasource attribute for the queries that use this database. The disadvantage is that your code becomes a little less consistent if some queries have a datasource attribute and others don't. That topic is best discussed in person while drinking beer.
or you can use the Applicaton.cfc this.datasources struct
Related
I have a “best-practices” question in regards to the correct way to instance CFCs that all need to talk to each other in a given project.
Let’s say for example you have a web application that has a bunch of different modules in it:
Online Calendar
Online Store
Blog
File Manager (uploading/downloading/processing files)
User Accounts
Each of these modules is nicely organized so that the functions that pertain to each module are contained within separate CFC files:
Calendar.cfc
Store.cfc
Blog.cfc
Files.cfc
Users.cfc
Each CFC contains functions appropriate for that particular module. For example, the Users.cfc contains functions pertaining to logging users on/off, updating account info etc…
Sometimes a CFC might need to reference a function in another CFC, for example, if the store (Store.cfc) needs to get information from a customer (Users.cfc). However, I'm not sure of the correct way to accomplish this. There are a couple ways that I've been playing with to allow my CFC's to reference each other:
Method 1: Within a CFC, instance the other CFC’s that you’re going to need:
<!--- Store.cfc --->
<cfcomponent>
<!--- instance all the CFC’s we will need here --->
<cfset usersCFC = CreateObject("component","users") />
<cfset filesCFC = CreateObject("component","files") />
<cffunction name="storeAction">
<cfset var customerInfo = usersCFC.getUser(1) />
This approach seems to work most of the time unless some of the instanced CFC’s also instance the CFC’s that instance them. For example: If Users.cfc instances Files.cfc and Files.cfc also instances Users.cfc. I’ve run into problems with occasional dreaded NULL NULL errors with this probably because of some type of infinite recursion issue.
Method 2: Instance any needed CFCs inside a CFC’s function scope (this seems to prevent the recursion issues):
<!--- Store.cfc --->
<cfcomponent>
<cffunction name="storeAction">
<!--- create a struct to keep all this function’s variables --->
<cfset var local = structNew() />
<!--- instance all the CFC’s we will need here --->
<cfset local.usersCFC = CreateObject("component","users") />
<cfset local.filesCFC = CreateObject("component","files") />
<cfset var customerInfo = local.usersCFC.getUser(1) />
My concern with this approach is that it may not be as efficient in terms of memory and processing efficiency because you wind up instancing the same CFC’s multiple times for each function that needs it. However it does solve the problem from method 1 of infinite recursion by isolating the CFCs to their respective function scopes.
One thing I thought of based on things I've seen online and articles on object oriented programming is to take advantage of a “Base.cfc” which uses the “extends” property of the cfcompontent tag to instance all of the CFC's in the application. However, I've never tested this type of setup before and I'm not sure if this is the ideal way to allow all my CFCs to talk to each other especially since I believe using extends overwrites functions if any of them share a common function name (e.g. "init()").
<!--- Base.cfc --->
<cfcomponent extends="calendar store blog users files">
What is the correct "best-practices" method for solving this type of problem?
If each of your CFC instances are intended to be singletons (i.e. you only need one instance of it in your application), then you definitely want to looking into Dependancy Injection. There are three main Dependancy Injection frameworks for CF; ColdSpring, WireBox and DI/1.
I'd suggest you look at DI/1 or WireBox as ColdSpring hasn't been updated for a while.
The wiki page for DI/1 is here:
https://github.com/framework-one/di1/wiki/Getting-Started-with-Inject-One
Wirebox wiki page is here:
http://wiki.coldbox.org/wiki/WireBox.cfm
Essentially what these frameworks do is to create (instantiate) your CFCs (beans) and then handles the dependancies they have on each other. So when you need to get your instantiated CFC it's already wired up and ready to go.
Dependancy Injection is also sometimes called IoC (inversion of control) and is a common design pattern used in many languages.
Hope that helps and good luck!
If your cfcs not related to each other the base.cfc concept does not fit. The inheritance is for classes have common things that can inherit from each other. For example if you have User.cfc and you want to added new cfc called customer.cfc I would inherit from User and override some functionality or add some without touching the actual user.cfc.
So, back to your question, since the CFC are not related or have common between each other and to avoid cross referencing, I will create serviceFactory holds instances of cfcs like this
component name="ServiceFactory"
{
function init(){
return this;
}
public User function getUserService(){
return new User();
}
public Calendar function getCalendar(){
return new Calendar();
}
}
and referencing it by
serviceFactory= new ServiceFactory();
userService = serviceFactory.getUserService();
Keep in mind this approach works only if you have sort of another CFC to manage your logic
you can do the same for all other services. If your functions are static you can save your services in application scope and instantiate it only one time (like singleton).
The third option you have is DI(dependency Injection) framework
As my application has grown, I've noticed that I am reusing a lot of database queries across multiple webpages.
At the moment I have done it using a .CFM file which has many <cfstoredproc> tags that gets included on every page that needs database data. All I am doing is wrapping these stored procedure executions in a <cfif> tag which tests what the name of the calling page is and then executes the appropriate <cfstoredproc> block of code.
I am no expert in anything, but this doesn't feel right to me. I just don't know how to manage all my database queries correctly so that they can be shared across any CFM page in the entire website. For example, one page might need the "GetUsers" stored procedure and another page might need "GetOrders".
I'm just about to embark on creating a CFC which holds every separate <cfstoredproc> or <cfquery> in its own method/function. E.g.:
<cfcomponent name="DBQueries" hint="Everything for DB retrieval">
<cffunction name="GetUsers" returntype="query">
<cfstoredproc procedure="GetUsers">
<cfprocresult name="rsUsers">
</cfstoredproc>
<cfreturn rsUsers>
</cffunction>
.....
<cffunction name="DBQuery100">
<cfstoredproc procedure="GetSomething" returntype="query">
<cfprocresult name="rsSomething">
</cfstoredproc>
<cfreturn rsSomething>
</cffunction>
</cfcomponent>
Then on a main .CFM page I will invoke the component and method required to return the data. Is this a good way to achieve DB query management?
The fact that it's database related is not as relevant as the fact that you have code repetition. You are on the right track in your effort to make the code more re-useable.
If you put your queries into a cfc, you might consider taking this one step further. Instead of invoking it all the time, use the onApplicationStart method of your Application.cfc to create an application variable that's available to all users on all pages.
Another approach is to put all these database tags into a .cfm file and to put a cfinclude in the onRequestStart method of your Application.cfc.
Both methods work. And, as is almost always the case when you compare two things, each has advantages over the other.
Consider the following two db tables
User
UserID PrimaryKey
firstname
lastname
Security
SecurityID PrimaryKey
UserID ForeignKey
Permission
All database tables have Create, Read, Update, Delete operations (CRUD)
CRUD operations can exist in several places
Inside of <cfquery> tags
Inside of Stored procedures
Others
The thing is all the CRUD operations belong together in their own way. Consider making a User object (user.cfc).
<cfcomponent>
<cffunction name="create"></cffunction>
<cffunction name="read"></cffunction>
<cffunction name="update"></cffunction>
<cffunction name="delete"></cffunction>
</cfcomponent>
Security is a part of user management, so is the object a one to one match to the db table? In some environments like ORM the answer is yes, in others not.
If you consider security to be a part of user managment, your user.cfc might look like this
<cfcomponent>
<cffunction name="create"></cffunction>
<cffunction name="read" hint="Read will also read security info"></cffunction>
<cffunction name="update" hint="Perhaps this can update security too"></cffunction>
<cffunction name="delete" hint="Delete will also delete security info"></cffunction>
<cffunction name="create_security"></cffunction>
<cffunction name="read_secrity" hint="This may not even be needed"></cffunction>
<cffunction name="update_security"></cffunction>
<cffunction name="delete_security" hint="This may not even be needed"></cffunction>
</cfcomponent>
At the end of the day you may find that you need far fewer objects (*.cfcs) than tables.
OK, now you have you user.cfc what do you do with it? It can be attached to you the rest of your app in various different ways
application.User = new user();
session.User = new user();
request.User = new user();
Each one of these is very from the next. Before we go down the road of which is appropriate, we have to consider member data, and how long we want it around.
<cfcomponent>
<cfset this.userid = ""><!--- This always points to the user I want to interact with --->
<cffunction name="create"></cffunction>
<cffunction name="read"></cffunction>
<cffunction name="update"></cffunction>
<cffunction name="delete"></cffunction>
</cfcomponent>
It is likely that your CRUD operations are going to interact with the same UserID for all their operations. You may find that after you update a record, you will often read it. Rather than always stating which UserID you are interacting with, you may just want to set it up once, and have all the functions just use the same one.
OK, now let's get back over to where you will be using them
application.User
Only one User object will exist in the the whole system. It will be created when the request comes in onthe site. This object will be shared for every request. If you attach your user object here, that suggests that all requests will be looking at the same user.
session.User
One User object will exist for a given end-user in the outside world. It will separated from all other end-users. This suggests that each end user will be looking at their own user AND that even as they click around the site, they will still be looking at the same user
request.User
One User object will exist per request. It will only exist for a particular request, and then be discarded. This suggests that looking at at particular User is meaningful on this request, but the next may be quite different, or maybe not even about users.
~~~~~~~~~~~~~~~
At the end of the day, you will need to decide how to bundle your DB interactions, and how long you will keep those bundled action together
I would have a model per table.
in there you have every query that ever does anything to that table
Lets say the Users table
Users.cfc
would have all the methods which return queries
getUsers - return alll users
getUserById - could be a paramater on the first function also.
Then when you need to work out where something in orders is being updated there is only one place to look.
I get the results like this
<cfset users = new model.Users().getUsers() />
or I use script
users = new model.Users().getUsers();
And if your really brave, try doing all the queries in script also.
One last thing to consider, if the data isn't changing, cache the query.
Things like OrderType or similar, you will get a lot of performance benefit rather than repeating the query over and over.
I've a variable in my Application.cfm that stores the datasource for cfqueries.
<cfset mydatasource= 'somedatasorce'>
I can use it in any normal cfm page as below:
<cfset any_var = #mydatasource#>
I've a cfm page that calls a cfc which builds a query dynamically. This is the URL Invocation Method of CFC.
I'm not able to access "mydatasource" in the CFC using the above statement. It says "mydatasource" is undefined. I tried storing this in Application scope & accessed in CFC but again it says "mydatasource" is undefined in "Application".
On a bit of search, I found that the CFC needs to be instantiated in order to access the Application scope. But the URL Invocation method doesn't create an instance.
I can pass the datasource using query string but I'm looking for a better & more secure alternative.
Any suggestions are highly appreciated.
Thanks!! :)
I have been adding a number of ajax calls to an old application here and in order to get some application specific settings I created a file I called App.cfc. The contents of it are simply:
<cfcomponent>
<cfscript>
this["datasource"] = "something";
..... and so on .....
</cfscript>
</cfcomponent>
Then the CFC files I am making my URL calls to they simple extend App. So within those CFCs I can do datasource="#this['Datasource']#"
May not be the most "pretty" of ways to get the job done but it has been working here without issues.
UPDATE
I should have also mentioned that in order to avoid having settings in both that CFC and in the Application.cfm, I have something like this in my Application.cfm:
<cfscript>
objApp = CreateObject("component", "Components.App");
StructAppend(App, objApp);
</cfscript>
These old applications I am working with have a structure withing VARIABLES called App that is a copy of all Application variables. I see no reason why in this case you could not just do a structure appending to VARIABLES since appears that is where you are expecting things like the datasource to be on in your CFM pages.
Does Coldfusion have a "Global" structure where the expressions global["FORM"], global["URL"], global["APPLICATION"], global["SESSION"], etc. are valid?
no. Form, URL, Application, Session etc are all 'global' already. The underlying Java has got this, if you just want to dump out all the scopes at once:
<cfdump var="#getPageContext().getBuiltInScopes()#">
Or at least that used to work, but in CF9 you have to use this instead:
<cfdump var="#getPageContext().getCFScopes()#">
Sorry, but the answer is, "Nope." (am I up to 30 characters yet?)
My take is that you are out of luck with FORM and URL scope.
You can access all user sessions running on a CF instance using SessionTracker Java object:
<cfset sessionTrackerObj = createObject("java","coldfusion.runtime.SessionTracker")>
<cfoutput><p>There are #sessionTrackerObj.getSessionCount()# active sessions</p></cfoutput>
Dump the sessionTrackerObj to view its structure.
The same goes for the APPLICATION scope:
<cfset appTrackerObj = createObject(“java”,”coldfusion.runtime.ApplicationScopeTracker”)>
Enjoy!
I have written a gateway to get a result set from my database. How do i store every row in a separate dao so that i can manipulate every record further? Or can i access the result set directly to get the records?
This is my Gateway (btw, should i write the conditional logic within the cfquery into a seperate cfc that extends this one?)
<cfcomponent name="MaterialDao" hint="data access object" output="false">
<cffunction name="init" hint="constructor" access="public" output="false" returntype="MaterialDao">
<cfargument name="dsn" type="String" required="true" hint="datasource" />
<cfset variables.instance.dsn = arguments.dsn />
<cfreturn this />
</cffunction>
<cffunction name="readMaterial" hint="read" access="public" output="false" returntype="Query">
<cfargument name="district" type="String" />
<cfset var qReadMaterial = "" />
<cfquery name="qReadMaterial" datasource="#variables.instance.dsn#">
<cfif StructKeyExists(arguments,"district")>
SELECT A.NR, A.BEZ, D.BES, D.STA
<cfelse>
SELECT A.NR, A.BEZ
</cfif>
FROM DEK AS D INNER JOIN ART AS A
ON D.NR = A.NR
WHERE 0=0
<cfif StructKeyExists(arguments,"district")>
AND D.BEZ = #arguments.district#
</cfif>
ORDER BY A.BEZ
</cfquery>
<cfreturn qReadMaterial />
</cffunction>
</cfcomponent>
I have already read a lot of articles and it seems that there are different opinions about this matter (DAO vs. Gateway, DAO & Gateway etc.). What is the best practice, what do the pros do?
The pros use just one pattern for the database access layer. The use of both a DAO and Gateway is a misnomer that I'm not really sure where it got started, but seems to only exist in the ColdFusion crowd. The DAO and Gateway patterns can pretty much serve the same function, but I think the DAO fits the bill more when talking about database interaction.
DAOs should include functionality for CRUD methods plus returning sets of records. Since CRUD and basic sets of records is highly repetitive, I use a code generator to create the code for this interaction and then customize what I need. This is a good place for conditional logic for selecting the records you need.
As Aaron mentioned, returning an array of objects for a set of records in your database is unfeasible in ColdFusion due the the performance overhead of creating objects. I typically just use the basic query returned from the DAO in my views. However, if the thing I'm modeling needs some behavior in a view, then I will put the query in an object using something similar to what Peter Bell does.
Peter Bell had a great presentation some months ago on his release of the Iterating Business Object CFC which allows you to take multiple records and iterate over one record at a time using this simple framework: http://ibo.riaforge.org/. Until CF is a little faster at generating objects, recycling a single instance of an object and repopulating the properties is likely your best best. Perhaps this can help you load one record at a time into your DAO.
Conditional logic can go in the Gateway or in a Manager CFC. Typically, I would include logic that is simple like the logic outlined in your post directly in the CFC.
A bit of advice, you may wish to make the arguments.distinct NOT required and do a simple check with if (structKeyExists(arguments, "distinct") ) { do something }.
Regards,
-Aaron Greenlee
At our company we thought long and hard about this stuff for a few months, trying the Adobe CF DAO creator via RDS and some other older ones (anyone remember CFPowerTools?).
We decided in the end to write our own DAO code generator and I thought I'd share our thoughts here. The reason we decided was because we needed to add locking hints to out SQL, we wanted to make it more efficient, more secure and cleaner.
The setup we decided on was to create a pre-defined base DAO object (called DAO.cfc) which all generated 'table' DAOs extended. All it had was a few utility methods, but the key thing thing is we can add any other functions in there that we need all our generated DAOs to have access to.
So we auto-generate code by selecting a table from the database (using the CF admin API) and create the [TableName].cfc DAO with the usual init, setters and getters, so the basic CRUD stuff.
In addition to this, we also generate a [TableName]GatewayBase.cfc and a [TableName]Gateway.cfc. [TableName]Gateway.cfc extends [TableName]GatewayBase.cfc.
So for a sample DAO run on a table called 'Customers', the files created are:
Customers.cfc /* extends DAO.cfc [not created, already exists] */
CustomersGateway.cfc
CustomersGatewayBase.cfc /* extends CustomersGateway */
So, the idea is that the gateway provides a way to deal with many 'Customer' records - the DAO is used when dealing with one and only one. All methods in the gateway will generally return a CF query object. CF is too inefficient to create massive arrays of DAO objects and in our mind the query object in CF is really flexible, so we're happy to use it.
When coding, the sub-class CustomerGateway.cfc is the only one instantiated and used. However, the base class it extends has some very useful generic functions that come for free, such as getFieldListByProperty() which based on passed parameters will return certain fields (i.e. table columns) by a certain property (i.e. a column value), so for example:
myGateway.getFieldListByProperty(property="status", value="1", fieldList="customerName,customerID", orderBy="createdOn") />
That call will return the 'customerName' and 'customerID' values for all customers with a status of 1, ordered by the date they were created on. The code is also hardened against SQL injection and validated so sensible exceptions are thrown.
This function will provide 99% (we hope!) of the multi-record querying you do on a table. If you need a more sophisiticated query then the CustomerGateway.cfc is there for you to add functions to.
Finally, we allow you add functions to CustomerGateway CFC only because if you change the customers table (say add a column), you will need to recreate the table, and tha will overwrite the Customers.cfc and the CustomersGatewayBase.cfc. However, your custom code (if any) is safe in the sub-class.
Anyway, this might be slightly off topic, but sure I thought someone might find our experience useful.