Choosing DAO, gateway, scaffolding, framework and generator - build your own!

February 21, 2008

In the past couple of months I’ve built two applications, one which uses DAO, the other uses Gateway to see which is best. My conclusion: use whichever one suits your needs at the time!

There are a multitude of code generator projects out there and they are all great, however it is unlikely that you won’t have to modify the code in someway to make it fit your needs. So, why not build your own code generator?

I’ve built one which has proved really useful as it builds the Gateway, basic CRUD forms (including JQuery validation) and Fusebox framework with server side validation. It wouldn’t suit everyone or every project but it works for me.

If you do want to try it yourself then have a look at the <cfdbinfo> tag. It’s incredibly powerful. I use MS SQL server 99% of the time so my generator makes use of some SQL statements and some cfdbinfo information. The basic functions you’ll need to build your own are:

<cffunction name="getUserTables"
  returntype="query"
  hint="I return all the user tables for a datasource">
  <cfargument name="datasource" required="yes" type="string" />

  <cfset var qryTables = "" />

  <cfquery name="qryTables" datasource="#Arguments.Datasource#">
    SELECT Table_Name
    FROM INFORMATION_SCHEMA.TABLES
    WHERE Table_Type = 'BASE TABLE'
      AND Table_Name <> 'dtproperties'
    ORDER BY Table_Name
  </cfquery>

  <cfreturn qryTables />
</cffunction>
<cffunction name="getTableFields"
  returntype="query"
  hint="I return all the fields and schema information for a given table">
  <cfargument name="tablename" required="yes" type="string" />
  <cfargument name="datasource" required="yes" type="string" />

  <cfset var qryTableFields = "" />

  <cfdbinfo datasource="#Arguments.Datasource#"
    table="#Arguments.tablename#"
    name="qryTableFields"
    type="columns" />

  <cfreturn qryTableFields />
</cffunction>
<cffunction name="getTablePrimaryKey"
  returntype="query"
  hint="I return the fields that make up the primary key for a given table">
  <cfargument name="tablename" required="yes" type="string" />
  <cfargument name="datasource" required="yes" type="string" />

  <cfset var qryPrimaryKey = "" />

  <cfquery name="qryPrimaryKey" datasource="#Arguments.Datasource#">
    SELECT Column_Name
    FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
      INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu
        ON tc.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME
    WHERE tc.Table_Name = <cfqueryparam value="#Arguments.tablename#" cfsqltype="cf_sql_varchar" />
      AND CONSTRAINT_TYPE = 'PRIMARY KEY'
  </cfquery>

  <cfreturn qryPrimaryKey />
</cffunction>
<cffunction name="getCFDataType" returntype="string" hint="I return the cfsqltype for the cfqueryparam function">
  <cfargument name="type" required="yes" type="string" />

  <cfset var private = StructNew() />
  <cfswitch expression="#ListFirst(LCase(Trim(Arguments.Type)), ' ')#">
    <cfcase value="bigint">
      <cfset private.CFDataType = "CF_SQL_BIGINT" />
    </cfcase>
    <cfcase value="binary,image,sql_variant,sysname,varbinary" />
      <cfset private.CFDataType = "">
    </cfcase>
    <cfcase value="bit">
      <cfset private.CFDataType = "CF_SQL_BIT" />
    </cfcase>
    <cfcase value="char,nchar">
      <cfset private.CFDataType = "CF_SQL_CHAR" />
    </cfcase>
    <cfcase value="datetime,smalldatetime">
      <cfset private.CFDataType = "CF_SQL_DATE" />
    </cfcase>
    <cfcase value="decimal">
      <cfset private.CFDataType = "CF_SQL_DECIMAL" />
    </cfcase>
    <cfcase value="float">
      <cfset private.CFDataType = "CF_SQL_FLOAT" />
    </cfcase>
    <cfcase value="int">
      <cfset private.CFDataType = "CF_SQL_INTEGER" />
    </cfcase>
    <cfcase value="money">
      <cfset private.CFDataType = "CF_SQL_MONEY" />
    </cfcase>
    <cfcase value="ntext,text">
      <cfset private.CFDataType = "CF_SQL_LONGVARCHAR" />
    </cfcase>
    <cfcase value="numeric">
      <cfset private.CFDataType = "CF_SQL_NUMERIC" />
    </cfcase>
    <cfcase value="nvarchar,varchar">
      <cfset private.CFDataType = "CF_SQL_VARCHAR" />
    </cfcase>
    <cfcase value="real">
      <cfset private.CFDataType = "CF_SQL_REAL" />
    </cfcase>
    <cfcase value="smallint">
      <cfset private.CFDataType = "CF_SQL_SMALLINT" />
    </cfcase>
    <cfcase value="smallmoney">
      <cfset private.CFDataType = "CF_SQL_MONEY4" />
    </cfcase>
    <cfcase value="timestamp">
      <cfset private.CFDataType = "CF_SQL_TIMESTAMP" />
    </cfcase>
    <cfcase value="tinyint">
      <cfset private.CFDataType = "CF_SQL_TINYINT" />
    </cfcase>
    <cfcase value="uniqueidentifier">
      <cfset private.CFDataType = "CF_SQL_IDSTAMP" />
    </cfcase>
    <cfdefaultcase>
      <cfthrow message="unknown datatype" />
    </cfdefaultcase>
  </cfswitch>

  <cfreturn Trim(private.CFDataType) />
</cffunction>

I’m not going to go into building the actual scripts as there are so many different ways it can be done. I hope this inspires someone!?


No comments

Leave a comment

If you found this post useful, interesting or just plain wrong, let me know - I like feedback :)

Please note: If you haven't commented before, then your comments will be moderated before they are displayed.