RE: Deploying to Multiple Databases

2003-10-29 Thread Matt Robertson
I try to avoid needing platform-specific sql during the app's initial
construction.May be too late or impossible for you to go down that
road.

Using CF to produce things like the date value from your example instead
of using the db's native functions eliminates the need to worry about
db-specific functions.As a rule I just do without db functions and set
values outside of cfquery.

This may mean compromising performance, but generally, for my own needs,
this has been extremely rare.For the exceptions where it can't be done
(for example, using a sequence for an insert on Oracle) its pretty easy
to write a bit of conditional sql

cfquery 
 datasource=#request.myDSN#
 INSERT INTO myfile
(cfif not Compare(myCachedQuery.DB,2)ID,/cfif
Blah)
 VALUES 
(cfif not Compare(myCachedQuery.DB,2)seq_myfile.nextval,/cfif
cfqueryparam cfsqltype=CF_SQL_VARCHAR value=#form.Blah#)
/cfquery

In cases where there's no way around doing fully custom sql I'll put the
conditional sql inside of a case statement; but for me it's a rare need.


 Matt Robertson [EMAIL PROTECTED] 
 MSB Designs, Inc.http://mysecretbase.com



 [Todays Threads] 
 [This Message] 
 [Subscription] 
 [Fast Unsubscribe] 
 [User Settings]




RE: Deploying to Multiple Databases

2003-10-29 Thread Haggerty, Mike
Jim -

Thanks for the feedback. As far as using a Web service is concerned, I
am trying to write this for the lowest common denominator and want to
avoid doing anything people might be unfamilar with or not be able to
use. CFMX is still a little too new for some organizations I want to
target with this app.

What do you think about calling all queries within a custom tag that
will determine the right statement based on the db type? In other words,
I would break out all the conditional SQL into separate queries that
would be called within a custom tag and passed back to the application. 

I am concerned this method might lead to too much overhead, because I
don't really know how CF handles recordsets in this situation. Does CF
create a duplicate recordset in the calling page, or does the calling
page reference the one in the custom tag?

(Details, details...)

M

-Original Message-
From: Jim Davis [mailto:[EMAIL PROTECTED] 
Sent: Wednesday, October 29, 2003 1:24 AM
To: CF-Talk
Subject: RE: Deploying to Multiple Databases

Using CFCs I do this:

I've got a DPDataSource CFC which has four proerties: DSNName, DBType,
UserName and Password.

The DBType is the important bit.For example, it may be
MSSQLServer2000 and determines which codebase to use.

Now, I place all of my data access methods into a broker CFC which is
utilized by the base class (I just do this to keep the size of the CFCs
down a little).Anyway my broker handles how to call the DB-specific
files.For example here is the save method from one of my brokers:

!--- Create/Update Artist ---
cffunctionname=save
hint=Saves Artist information to the database.
returntype=void
access=public
output=No

!--- Attempt to include the relevant
implementation file based on the DataSource type file ---
cftry
cftransaction action="">
isolation=SERIALIZABLE
cfinclude
template=DB_#this.DPDataSource.getType()#\ArtistBroker_save.cfm
/cftransaction
!--- Catch Errors ---
cfcatch type=MissingInclude
cfset
this.DPException.new(DPEvents.Artist.Broker.MissingImplementationFile,
No ArtistBroker_save implementation file for DataSource type
#this.DPDataSource.getType()# exists.)
cfset this.DPException.throw()
/cfcatch
cfcatch type=Any
cfrethrow
cfset
this.DPException.new(DPEvents.Artist.Broker, An error occured
attempting to save the Artist., cfcatch)
cfset this.DPException.throw()
/cfcatch
/cftry

/cffunction

Note that the method itself doesn't have any SQL in it - rather it uses
the value in the DPDataSource component to include the proper file from
a directory named after the value.So my directories may look like
this:

Cfcs
- - DB_MSSQLServer2000
- - DB_MSSQLServer65
- - DB_MySQL

And so forth.The include files are as complex as the DB needs (most
often just simple statements) but may contain multiple actions.The
application layer may expect back a query (or queries) and do more work
after the try/catch block.In effect you specify what the include needs
and what it will return.

There many benefits to this (I think):

1) You can add a new database very easily: a new directory with that DBs
code and a very simple change to the DataSource component created.

2) The same set of components can be used for ALL supported database
simultaneously (by instantiated them with different datasource
components).By leveraging the components this also opens up the
ability to easily create conversion tools - instantiate one component on
SQL Server and another on Oracle, trade the data between the CFCs, then
save.No direct DB integration needed, but full conversion
compatibility.

3) As long as you defined the needed output from the includes (query
objects usually) you don't NEED a database.Your datatype could be
XML for example and your includes could manage a bunch of XML files:
as long as you generated the proper queries to return to the application
from that XML.In other words the implementation doesn't assume SQL -
but it might assume it's getting back queries.

You could just create multiple brokers - but dynamic CFC names are
impossible in some cases and just plain hard in all others - it's just
not worth it (you really have to have several sets of brokers which you
swap in and out).

I'm not sure if any of that rambling made sense. ask if it didn't!

Jim Davis

-Original Message-
From: [EMAIL PROTECTED] [EMAIL PROTECTED]
[mailto:[EMAIL PROTECTED] 
Sent: Tuesday, October 28, 2003 11:46 PM
To: CF-Talk
Subject: Deploying to Multiple Databases

I have a question about deploying an application into multiple
environments, and am looking for any lessons learned from people who
have done this. This is almost an aesthetics question.

Essentially, there is this app I built that is intended to run using
either MS-SQL or MySQL, and I want to come up with the best way to
package the SQL statements. Other developers will probably want to work
with the code someday, so I want to make sure the code is as easy to
understand as possible.

Right now I have a req

RE: Deploying to Multiple Databases

2003-10-29 Thread Jim Davis
Actually I haven't done anything with Web Services (yet) - if you're
under the impression that CFCs are only for constructing Web Services
then you're way off (and missing out on a HUGE productivity gain).;^)

 
You could (as you suggest) mimic the behavior with CustomTags however so
that's up to you.I wouldstill recommend using the same basic idea:
directories of include files with your DB-specific code and a broker
custom tag to call and manage them.You get pretty much all the
benefits I mentioned except for persistence (of the CFC).

 
This method will lead to MORE overhead, but I really doubt too much
overhead.In general, when programming, you have to trade performance
for maintainability and extensibility.The faster you make something,
the less portable, upgradeable and extensible it is.By the same token
the more extensible and portable you make things the slower they get.

 
As far your specific question - it depends.By default CF isolates all
CustomTag code into it's own memory space.However you can set the
query directly to the caller via the caller scope to eliminate double
memory usage by having a copy in the tag and a copy in the caller
(although the copy in the tag will be eliminated when the tag ends in
any case).

 
Personally I would begin by designing the perfect extensibility
architecture - forget completely about performance.Build a small
sample using it and another using direct DB calls then pound it a little
(run some tests).I think you'll be pleasantly surprised at the
(generally rather small) differences in performance: they'll rarely be
enough to scuttle the app.You can then focus on improving the
performance of your model.

 
This way: focusing on your problem and concepts initially but ignoring
technical considerations you almost always end up with a better system
(but don't forget to do the optimization phase at the end!)

 
Jim Davis

-Original Message-
From: Haggerty, Mike [mailto:[EMAIL PROTECTED] 
Sent: Wednesday, October 29, 2003 11:26 AM
To: CF-Talk
Subject: RE: Deploying to Multiple Databases

 
Jim -

Thanks for the feedback. As far as using a Web service is concerned, I
am trying to write this for the lowest common denominator and want to
avoid doing anything people might be unfamilar with or not be able to
use. CFMX is still a little too new for some organizations I want to
target with this app.

What do you think about calling all queries within a custom tag that
will determine the right statement based on the db type? In other words,
I would break out all the conditional SQL into separate queries that
would be called within a custom tag and passed back to the application. 

I am concerned this method might lead to too much overhead, because I
don't really know how CF handles recordsets in this situation. Does CF
create a duplicate recordset in the calling page, or does the calling
page reference the one in the custom tag?

(Details, details...)

M

-Original Message-
From: Jim Davis [mailto:[EMAIL PROTECTED] 
Sent: Wednesday, October 29, 2003 1:24 AM
To: CF-Talk
Subject: RE: Deploying to Multiple Databases

Using CFCs I do this:

I've got a DPDataSource CFC which has four proerties: DSNName, DBType,
UserName and Password.

The DBType is the important bit.For example, it may be
MSSQLServer2000 and determines which codebase to use.

Now, I place all of my data access methods into a broker CFC which is
utilized by the base class (I just do this to keep the size of the CFCs
down a little).Anyway my broker handles how to call the DB-specific
files.For example here is the save method from one of my brokers:

!--- Create/Update Artist ---
cffunctionname=save
hint=Saves Artist information to the database.
returntype=void
access=public
output=No

!--- Attempt to include the relevant
implementation file based on the DataSource type file ---
cftry
cftransaction action="">
isolation=SERIALIZABLE
cfinclude
template=DB_#this.DPDataSource.getType()#\ArtistBroker_save.cfm
/cftransaction
!--- Catch Errors ---
cfcatch type=MissingInclude
cfset
this.DPException.new(DPEvents.Artist.Broker.MissingImplementationFile,
No ArtistBroker_save implementation file for DataSource type
#this.DPDataSource.getType()# exists.)
cfset this.DPException.throw()
/cfcatch
cfcatch type=Any
cfrethrow
cfset
this.DPException.new(DPEvents.Artist.Broker, An error occured
attempting to save the Artist., cfcatch)
cfset this.DPException.throw()
/cfcatch
/cftry

/cffunction

Note that the method itself doesn't have any SQL in it - rather it uses
the value in the DPDataSource component to include the proper file from
a directory named after the value.So my directories may look like
this:

Cfcs
- - DB_MSSQLServer2000
- - DB_MSSQLServer65
- - DB_MySQL

And so forth.The include files are as complex as the DB needs (most
often just simple statements) but may contain multiple actions.The
application layer may expect back a query (or queries) and do more work
after the try/catch block.In effec

RE: Deploying to Multiple Databases

2003-10-28 Thread Jim Davis
Using CFCs I do this:

 
I've got a DPDataSource CFC which has four proerties: DSNName, DBType,
UserName and Password.

 
The DBType is the important bit.For example, it may be
MSSQLServer2000 and determines which codebase to use.

 
Now, I place all of my data access methods into a broker CFC which is
utilized by the base class (I just do this to keep the size of the CFCs
down a little).Anyway my broker handles how to call the DB-specific
files.For example here is the save method from one of my brokers:

 
!--- Create/Update Artist ---
cffunctionname=save
hint=Saves Artist information to the database.
returntype=void
access=public
output=No

 
!--- Attempt to include the relevant
implementation file based on the DataSource type file ---
cftry
cftransaction action="">
isolation=SERIALIZABLE
cfinclude
template=DB_#this.DPDataSource.getType()#\ArtistBroker_save.cfm
/cftransaction
!--- Catch Errors ---
cfcatch type=MissingInclude
cfset
this.DPException.new(DPEvents.Artist.Broker.MissingImplementationFile,
No ArtistBroker_save implementation file for DataSource type
#this.DPDataSource.getType()# exists.)
cfset this.DPException.throw()
/cfcatch
cfcatch type=Any
cfrethrow
cfset
this.DPException.new(DPEvents.Artist.Broker, An error occured
attempting to save the Artist., cfcatch)
cfset this.DPException.throw()
/cfcatch
/cftry

 
/cffunction

 
Note that the method itself doesn't have any SQL in it - rather it uses
the value in the DPDataSource component to include the proper file from
a directory named after the value.So my directories may look like
this:

 
Cfcs
 - - DB_MSSQLServer2000
 - - DB_MSSQLServer65
 - - DB_MySQL

 
And so forth.The include files are as complex as the DB needs (most
often just simple statements) but may contain multiple actions.The
application layer may expect back a query (or queries) and do more work
after the try/catch block.In effect you specify what the include needs
and what it will return.

 
There many benefits to this (I think):

 
1) You can add a new database very easily: a new directory with that DBs
code and a very simple change to the DataSource component created.

 
2) The same set of components can be used for ALL supported database
simultaneously (by instantiated them with different datasource
components).By leveraging the components this also opens up the
ability to easily create conversion tools - instantiate one component on
SQL Server and another on Oracle, trade the data between the CFCs, then
save.No direct DB integration needed, but full conversion
compatibility.

 
3) As long as you defined the needed output from the includes (query
objects usually) you don't NEED a database.Your datatype could be
XML for example and your includes could manage a bunch of XML files:
as long as you generated the proper queries to return to the application
from that XML.In other words the implementation doesn't assume SQL -
but it might assume it's getting back queries.

 
You could just create multiple brokers - but dynamic CFC names are
impossible in some cases and just plain hard in all others - it's just
not worth it (you really have to have several sets of brokers which you
swap in and out).

 
I'm not sure if any of that rambling made sense. ask if it didn't!

 
Jim Davis


-Original Message-
From: [EMAIL PROTECTED] [EMAIL PROTECTED]
[mailto:[EMAIL PROTECTED] 
Sent: Tuesday, October 28, 2003 11:46 PM
To: CF-Talk
Subject: Deploying to Multiple Databases

 
I have a question about deploying an application into multiple
environments, and am looking for any lessons learned from people who
have done this. This is almost an aesthetics question.

Essentially, there is this app I built that is intended to run using
either MS-SQL or MySQL, and I want to come up with the best way to
package the SQL statements. Other developers will probably want to work
with the code someday, so I want to make sure the code is as easy to
understand as possible.

Right now I have a request variable in a settings file (this is a
Fusebox application) that tells CF to use either the MySQL or the MSSQL
version of the query language. Consequently, all of my queries look like
this beast:

cfquery name=qry_get_event datasource=#request.dsn#
cfif request.dbtype EQ mssql
SELECT TOP 1 event_title, event_desc, event_date
FROM abc_event
WHERE ev_active = 1
ORDER BY event_date
cfelseif request.dbtype EQ mysql
SELECT event_title, event_desc, event_date
FROM abc_event
WHERE ev_active = 1
ORDER BY event_date
LIMIT 1
/cfif
/cfquery

Also, I set a range of variables corresponding to various functions in
each db, i.e. GETDATE() and CURRENT_DATE() are output by CF throughout
the code.

My thoughts are that this is too convoluted, and anyone having to
support the code is going to have headaches (especially after I add the
PostGres, DB2 and Oracle support). So I am going to rewrite the code, I
just don't know what approach to take.

The idea I had was to move all the query statements into separate files
based on