Transfer ORM Cheat Sheet

December 09, 2008

A little quick start guide I've put together for Transfer ORM

Initialising Transfer (as a Singleton)


<cfset application.transferFactory =
createObject("component", "transfer.TransferFactory").init(
"/config/datasource.xml.cfm",
"/config/transfer.xml.cfm",
"/config/definitions") /
>


<!--- shorthand reference to getTransfer --->
<cfset Application.transfer = application.transferFactory.getTransfer() />

datasource.xml.cfm

<?xml version="1.0" encoding="UTF-8"?>
<datasource 
  xsi:noNamespaceSchemaLocation="../transfer/resources/xsd/datasource.xsd" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <name>aliaspooryorik</name>
  <username></username>
  <password></password>
</datasource>

transfer.xml.cfm

<?xml version="1.0" encoding="UTF-8"?>
<transfer 
  xsi:noNamespaceSchemaLocation="../transfer/resources/xsd/transfer.xsd" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <objectDefinitions>
    <object name="Post" table="BlogPosts">
      <!-- 
      ---------------------------------------------------------
      attributes
      ---------------------------------------------------------
      name
      required
      type
      required
      [numeric|string|date|boolean|UUID|GUID] 
      column
      optional (default: name)
      generate
      optional
      [true|false]
      nullable
      optional (default: false)
      --------------------------------------------------------- 
      -->
      <id name="id" column="post_id" type="numeric" generate="true" />
      <property name="status" type="boolean" column="post_status" nullable="false" />
      <property name="title" type="string" column="post_title" nullable="false" />
      <property name="views" type="string" column="post_views" nullable="false" />
    </object>
  </objectDefinitions>
</transfer>

A couple of gotchas to look out for before we even start any code!

  1. The object name is case sensitive!
  2. You will need to create the 'definitions' directory - Transfer will not do that for you!

Get an object by id


<cfset post = application.transfer.get("Post", 1) />

Debugging (only use getMemento for debugging)


<cfset post = application.transfer.get("Post", 1) />
<cfdump var="#post.getMemento()#" />

Displaying values


<cfset post = application.transfer.get("Post", 1) />
<cfoutput>
Name: #post.getTitle()#
</cfoutput>

Delete an object by id


<cfset post = application.transfer.get("Post", 1) />
<cfset application.transfer.delete(post) />

Create an empty object (preferred)


<cfset post = application.transfer.new("Post") />

Create an empty object (alternative)


<cfset post = application.transfer.get("Post", 0) />

Note that there must not be a post object with an id of 0.

Save a new object


<cfset post = application.transfer.new("Post") />
<cfset post.setTitle("Transfer is mighty impressive!") />
<cfset application.transfer.save(post) />

Update an existing object


<cfset post = application.transfer.get("Post", 1) />
<cfset post.setTitle("Transfer is not as complicated as you think!") />
<cfset application.transfer.save(post) />

Getting an query object ordering by 'title' property ascending (A-Z)


<cfset posts = application.transfer.list("Post", "title") />
<cfdump var="#posts#" />

Getting an query object ordering by 'title' property descending (Z-A)


<cfset posts = application.transfer.list("Post", "title", false) />
<cfdump var="#posts#" />

Getting an query object filtering by a property


<cfset activeposts = application.transfer.listByProperty("Post", "status", True) />
<cfdump var="#activeposts#" />

Getting an query object filtering by multiple properties


<cfset map = StructNew() />
<cfset map.views = 0 />
<cfset map.status = True />
<cfset activepostswithnoviews = application.transfer.listByPropertyMap("Post", map) />
<cfdump var="#activepostswithnoviews#" />

Decorators (are cool!)

Add the component path to the Transfer XML config file


<object name="User" table="users" decorator="model.transferdecorators.user">

An example decorator


<cfcomponent extends="transfer.com.TransferDecorator" displayname="User" output="false">
<cffunction name="getAgeInYears"
access="public"
returntype="numeric"
output="false"
hint="I am a new method">

<cfreturn DateDiff( 'y', getDateOfBirth(), Now() ) />
</cffunction>
<cffunction name="getImage"
access="public"
returntype="numeric"
output="false"
hint="I override the default getImage method">


<!--- need to use the getTransferObject() method to access the original method --->
<cfset var imagefilename = getTransferObject().getImage() />
<cfif imagefilename eq "">
<cfset imagefilename = "stub-profile-image.jpg" />
</cfif>
<cfreturn imagefilename />
</cffunction>
</cfcomponent>

Using onetomany Compositions

In this Transfer snippet, one Bookshelf can have many Books, so use a onetomany composition.


<object name="Bookshelf">
<id name="BookshelfID" type="numeric" />
<property name="Name" type="string" />
<onetomany name="Book" lazy="true" proxied="true">
<link column="fk_bookshelfid" to="Book" />
<collection type="array">
<order property="Name" order="asc" />
</collection>
</onetomany>
</object>

To get an array of Books you'd do this.


<cfset Bookshelf = application.transfer.get( "Bookshelf", 1 ) />
<cfset Book = Bookshelf.getBookArray() />

TQL (Transfer Query Language)

Transfer allows you to write your own queries. It is worth noting that unlike SQL statements, TQL statements are executed against your objects, not the database tables.

It is important to note that if you are adding the TQL inside a cffunction tag which has the attribute of output="false", then you will need to wrap the TQL in a cfoutput tag.


<cfsavecontent variable="tql">
SELECT Book.Name
, Bookshelf.Name
FROM library.Book as Book
JOIN library.Bookshelf as Bookshelf
WHERE Bookshelf.BookshelfID = :id
ORDER BY Bookshelf.Name
</cfsavecontent>

<cfset query = getTransfer().createQuery( tql ) />
<cfset query.setParam( "id", "1", "numeric" ) />
<cfset result = getTransfer().listByQuery( query ) />

Using the TQL Custom Tags


<cfimport prefix="t" taglib="/transfer/tags" />
<t:query name="result" transfer="#getTransfer()#">
SELECT Book.Name
, Bookshelf.Name
FROM library.Book as Book
JOIN library.Bookshelf as Bookshelf
WHERE Bookshelf.BookshelfID = <t:queryparam value="#id#" type="GUID">
ORDER BY Bookshelf.Name
</t:query>

If you use joins then Transfer knows how to construct the relationship by using the compositions you set up in Transfer.xml.


4 comments

  1. Thanks for posting this. Found it very helpful.

    Comment by Josh Grauer – January 21, 2009
  2. Cool Tutorial! Could you please tell me how to get just 5 Records, like "SELECT TOP 5 FROM comments ORDER BY posted" with Transfer? Because i just can start the TSL with the Keyword FROM?

    Comment by Reinhard Jung – August 10, 2009
  3. Hey Reinhard. Glad you found the info useful. I'm not 100% sure, but I don't think that Transfer support "top x".

    You might want to try posting to the mailing list:
    groups.google.com/group/transfer-dev

    Comment by John Whish – August 13, 2009
  4. Hi

    Just started using Transfer and this cheat sheet has proved valuable in getting head round it!

    Comment by jbuda – March 12, 2010

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.