Blog Projects
Escape Keys
A ColdFusion and Web Development Blog by Tom de Manincor
 
Postgre Error: Relation does not exist

I'm working on an app that integrates with the Transfer ORM. The code runs on an MS SQL and MySQL database without a problem. However, when switching over to Postgre one table causes things to flop.

When it queries the table i get the error: relation "tableName" does not exist.

I look at the SQL involved and its a basic select. So I try select * tableName, and get the same error in the query window.

If I add double quotes around "tableName" it works fine.

That's a solution but not an explanation for the problem.

Why is it, that for this tableName, I need the double quotes?

Well it can be one of two things...

The tableName is a reserved word in Postgre or when you created the table you used mixed cases (tableName) or upper case (TABLENAME). Had you created the table lower case (tablename) then you would have never seen this error. So if you are using an ORM that extends itself to Postgre be sure to create tables and column names in lower case.

Using a Decorator with Transfer

Transfer was built to allow you to extend its capabilities. Using the Decorator Pattern you can overlay/overwrite methods of a TransferObject and add methods of your own. Remember its a Decorator to the Transfer Object(the Bean). So the methods you add should be relative to the Bean. To add DB or other external functions, there are other ways.

Here's how you setup the Decorator.

1. Add the decorator attribute to the object element in your Transfer Config XML file.

<objectDefinitions>
<package name="Account">
<object name="Account" table="Account" decorator="model.account.accountDecorator" >
<id name="AccountId" type="UUID" generate="true"/>
<property name="Username" type="string" nullable="false" />
<property name="Password" type="string" nullable="false" />
<property name="FirstName" type="string" nullable="true" />
<property name="LastName" type="string" nullable="true" />
<property name="Email" type="string" nullable="false" />
<property name="UpdatedOn" type="date" nullable="false" />
<property name="CreatedOn" type="date" ignore-update="true" />
</object>
</package>
</objectDefinitions>

2. Create your Decorator CFC and extend the Transfer Decorator Object.

<cfcomponent displayname="accountDecorator" hint="Decorates Account TransferObject" output="false" extends="transfer.com.TransferDecorator">

<cffunction name="setPassword" access="public" returntype="void" output="false" hint="Replaces original setPassword to MD5 Hash the Password">
<cfargument name="password" type="string" required="true" />
<cfset getTransferObject().setPassword(hash(password)) />
</cffunction>

</cfcomponent>

You also have access to getTransfer() when you extend the Transfer Decorator Object.

That's it. Re-init Transfer and your Decorator methods will now be available from your Transfer Objects.

To take it a step further, I have created a Base Decorator to share methods accross Decorators. But that's another Blog.

Extending a Base Decorator with Transfer

So you have a few methods you want to include in every Transfer Object, and you don't want mess with mix-ins, and copy/paste isn't an option. You want to extend it but its already extending the transfer.com.TransferDecorator. So what can you do?

1. Create your Base Decorator CFC, and extend the transfer.com.TransferDecorator.

<cfcomponent displayname="baseDecorator" hint="This is the baseDecorator component" output="false" extends="transfer.com.TransferDecorator">

<cffunction name="listProperties" access="public" returntype="string" output="false" hint="Returns a List of the Properties">
<cfset var lReturn = '' />
<cfset var oIterator = getTransfer().getTransferMetaData(this.getClassName()).getPropertyIterator() />

<cfloop condition="#oIterator.hasNext()#">
<cfset lReturn = listAppend(lReturn,oIterator.next().getName()) />
</cfloop>

<cfreturn lReturn />
</cffunction>

<cffunction name="listColumns" access="public" returntype="string" output="false" hint="Returns a List of the Properties">
<cfset var lReturn = '' />
<cfset var oIterator = getTransfer().getTransferMetaData(this.getClassName()).getPropertyIterator() />

<cfloop condition="#oIterator.hasNext()#">
<cfset lReturn = listAppend(lReturn,oIterator.next().getColumn()) />
</cfloop>

<cfreturn lReturn />
</cffunction>

</cfcomponent>

2. Now change the 'extends' in the object decorator to extend the Base Decorator CFC

<cfcomponent displayname="accountDecorator" hint="This is the accountDecorator component" output="false" extends="model.baseDecorator">

<cffunction name="setPassword" access="public" returntype="void" output="false" hint="Replaces default setPassword method to MD5 Hash the Password">
<cfargument name="password" type="string" required="true" />
<cfset getTransferObject().setPassword(hash(password)) />
</cffunction>

</cfcomponent>

Now you'll have the baseDecorator and the accountDecorator methods available to you from your TransferObject.

Wait...What if you only need to extend the baseDecorator to your TransferObject and don't forsee a need for an accountDecorator? Dont create an empty accountDecorator just to extend the baseDecorator.

Change the value of the decorator attriute in the Transfer Config XML to the path of your baseDecorator.

<object name="Account" table="Account" decorator="model.baseDecorator" >