Get Objects from Transfer by Table Name
It's nice to be back in the world of ColdFusion at work, if temporarily. I am working on an idea for a Flex project where I am toying with using both ColdSpring and Transfer. For reasons I won't get into here, I wanted to try creating a generic base DAO that could handle all my CRUD via Transfer. This DAO would handle creating the Transfer object, populating it and inserting, updating or deleting it. However, I didn't want anything calling this base DAO to know that it used Transfer, I just wanted to pass a table name and a struct of properties.
To make a long story...well...short-er, this all led to a need to find a way to get an object by simply passing the table name. As far as I can tell having examined the Transfer docs, there isn't a way to retrieve Transfer's metadata information (other than by object) or its config file location even (please correct me if I am wrong...Mark?). This led me to simply reading the config file and parsing it, creating a structure that mapped table names to object names with packages in Transfer.
Anyway, below is some sample code I came up with to do this. It's not rocket science, mostly just basic XML parsing, but it works. I am not even sure I am going to use this idea (perhaps its more trouble than its worth), but I figured I'd share nonetheless.
<cfset variables.transfer = application.factory.getBean("transfer").getTransfer() />
<cffile action="read" file="#expandPath('/config/Transfer/Transfer.xml')#" variable="transferXML" />
<cfset packages = xmlSearch(transferXML,"//package") />
<cfset tableObjectMap = structNew() />
<cfset currentPackage = "" />
<cfloop array="#packages#" index="thisPackage">
<cfset currentPackage = thisPackage.XMLAttributes.name />
<!--- loop over the objects --->
<cfloop array="#thisPackage.xmlChildren#" index="thisObject">
<cfset tableObjectMap[thisObject.xmlAttributes.table] = currentPackage & "." & thisObject.xmlAttributes.name />
</cfloop>
</cfloop>
<cfset product = variables.transfer.new(tableObjectMap["products"])>
<cfdump var="#product.getClassName()#" />
In this scenario, the above code outputs "products.Product", which is the package and name of the object associated with the products table. Note, my thought at the moment would be to create this map at the same time as I instantiate ColdSpring (and thereby Transfer) and then pass it through. Like I said, I am not thrilled with my idea. Anyone have a better one?
Having said that, I'm not sure that I would choose to take that approach at all. It seems to me that by using the actual table name in your model you are tightly coupling it with the physical database, which seems like maybe something to avoid. In fact it seems like one of the benefits of an ORM is that it allows you to keep your physical database loosely coupled with your model. I would probably just use the transfer class name directly, and treat it as an arbitrary identifier of the table. If Transfer were removed from the equation in the future you'll still need an identifier for the table, so you could continue to use the transfer class name if you wanted. To keep your model abstracted from your physical database you need a map of identifiers to physical table names, which is essentially what transfer.xml is. Why not just use that map, and the identifiers that come with it?
Truth be told, I scrapped this idea for the project I am working on. Still, I could see potential uses for some of these features.
Yes a standard DAO would know what table it's using, but I thought you were trying to accomplish something different. Truth be told, what you seem to be describing is pretty close to the way I'm doing things, and I just use transfer class names, so that's what prompted me to comment.
Also, I wasn't suggesting using another map, I guess my message was less than coherent. I was just pointing out that you would need a map if you want to abstract the physical database out of the model (which perhaps is _not_ actually the goal), and that you already have a map, which is transfer.xml, so why not just use that? So basically, _don't_ use a map - use what you've already got, i.e., transfer class names.

