Transfer ORM Quickstart

2008 April 25
tags: Learning · Transfer
by Paul Marcotte
Transfer ORM is, as the name implies, an object relational mapper for Coldfusion. Transfer has a myriad of advanced features which can be intimidating for newcomers. Fortunately, Transfer can be installed and used very easily without learning some of the more advanced features. What follows are instructions you can use to install, configure and use transfer in a few simple steps.

Installation

UPDATE: Transfer 1.0 is now available. The last official release of transfer is 0.6.3. This version is now quite old and it is recommended that you use the bleeding edge release (BER) from subversion. If you have any misgivings about using the BER, rest assured that many production systems are running the transfer BER. It's stable. To install the transfer BER, point your subversion client to http://svn.riaforge.org/transfer and checkout or export the source from /trunk/transfer. You can either set a mapping for "/transfer" in the cf administrator, or drop the source transfer folder in your web root.

Configuration

To use transfer in an application you'll need to setup two configuration files. One for the datasource that transfer will use and another to describe the objects that transfer maps from your relational database. These files are typically named Datasource.xml and Transfer.xml, but you can use any name you like and/or append a .cfm extension to prevent the files from being visible in a web browser. Datasource.xml The transfer datasource.xml config specifies the values for the following: - a datasource name that currently exists in the cf administrator - a username (if required - leave blank otherwise) - a password (if required - leave blank otherwise) <?xml version="1.0" encoding="UTF-8"?>
<datasource xsi:noNamespaceSchemaLocation="../xsd/datasource.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<name>dsn_name</name>
<username></username>
<password></password>
</datasource>
Transfer.xml The transfer.xml file is used to define the properties and relationships of transfer objects that are mapped to the relational tables in your database. Objects can have onetomany, manytoone, or manytomany relationships. The following xml is the object definitions from the tBlog sample app. <?xml version="1.0" encoding="UTF-8"?>
<transfer xsi:noNamespaceSchemaLocation="../xsd/transfer.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<InvalidTagDefinitions>
<package name="user">
<!-- User details -->
<InvalidTag name="User" table="tbl_User">
<id name="IDUser" type="numeric"/>
<property name="Name" type="string" column="user_Name"/>
<property name="Email" type="string" column="user_Email"/>
</object>
</package>
<package name="system">
<!-- Different categories for Blog Posts -->
<InvalidTag name="Category" table="tbl_Category">
<id name="IDCategory" type="numeric"/>
<property name="Name" type="string" column="category_Name"/>
<property name="OrderIndex" type="numeric" column="category_OrderIndex"/>
</object>
</package>
<package name="post">
<!-- A Blog Post, with a Decorator of type com.Post -->
<InvalidTag name="Post" table="tbl_Post" decorator="tblog.com.Post">
<id name="IDPost" type="numeric"/>
<property name="Title" type="string" column="post_Title"/>
<property name="Body" type="string" column="post_Body"/>
<property name="DateTime" type="date" column="post_DateTime"/>
<!-- Link between a Post and the User it who wrote it -->
<manytoone name="User">
<link to="user.User" column="lnkIDUser"/>
</manytoone>
<!--
Link between a post and it's array of Comments
-->

<onetomany name="Comment">
<link to="post.Comment" column="lnkIDPost"/>
<collection type="array">
<order property="DateTime" order="asc"/>
</collection>
</onetomany>
<manytomany name="Category" table="lnk_PostCategory">
<link to="post.Post" column="lnkIDPost"/>
<link to="system.Category" column="lnkIDCategory"/>
<collection type="array">
<order property="OrderIndex" order="asc"/>
</collection>
</manytomany>
</object>
<!-- A comment for a blog post -->
<InvalidTag name="Comment" table="tbl_Comment">
<id name="IDComment" type="numeric"/>
<property name="Name" type="string" column="comment_Name"/>
<property name="Value" type="string" column="comment_Value"/>
<property name="DateTime" type="date" column="comment_DateTime"/>
</object>
</package>
</objectDefinitions>
</transfer>

Integration

Using Transfer with Coldspring <bean id="transferFactory" class="transfer.TransferFactory">
<constructor-arg name="datasourcePath"><value>/config/transfer/Datasource.xml</value></constructor-arg>
<constructor-arg name="configPath"><value>/config/transfer/Transfer.xml</value></constructor-arg>
<constructor-arg name="definitionPath"><value>/path/to/definitions</value></constructor-arg>
</bean>

<bean id="datasource" factory-bean="transferFactory" factory-method="getDatasource" />

<bean id="transfer" factory-bean="transferFactory" factory-method="getTransfer" />
Using transfer as an application scope "singleton". <cfset transferConfig = StructNew() />
<cfset transferConfig["datasourcePath"] = "/config/transfer/Datasource.xml" />
<cfset transferConfig["configPath"] = "/config/transfer/Transfer.xml" />
<cfset transferConfig["definitionPath"] = "/path/to/definitions" />
<cfset application.transferFactory = CreateObject("component","transfer.TransferFactory").init(argumentCollection=transferConfig) />
<cfset application.transfer = application.transferFactory.getTransfer() />

Usage

To grasp the full breadth of the transfer API, you really need to review the Transfer docs. I'll cover the four methods you will likely work with the most in the beginning. They are, get(), new(), save() and delete(). Using the tBlog object definitions above, to retrieve a post object use: <cfset application.transfer.get("post.Post",1) /> To have transfer return a new instance: <cfset post application.transfer.new("post.Post") /> To modify and save a new post: <!--- create a new post --->
<cfset post = application.transfer.new("post.Post") />
<!--- retrieve category with id 1 --->
<cfset category = application.transfer.get("system.Category",1) />
<!--- set properties (not shown) --->
<!--- set category for post --->
<cfset post.setCategory(category) />
<!--- save the post --->
<cfset application.transfer.save(post) />
A small, but significant, benefit of using Transfer ORM, is that when you save an new object the object's state reflects it's new persisted state. So you can find out the new id by simply calling. <cfset newid = post.getID() /> Lastly, transfer delete() method works like save(), you pass the transfer object to the method. <cfset application.transfer.delete(post) />

Much, much, more

This quick start is intended to help impatient types (like myself) get a taste for how simple it is to start using Transfer ORM. As you become comfortable with the Transfer API, you will definitely want to explore features like Transfer Object Decorators, the Transfer Event Model and Transfer Query Language (TQL). Mark Mandel has put a great deal of effort to into Transfer since it turned POSS. If you are not comfortable using the bleeding edge source code from subversion, keep an eye out for a 1.0 Release Candidate.