In today's Transfer entry I'm going to talk about getting objects in Transfer. I had previously talked about the get method and how it can load an object via a primary key, but what about other methods of finding objects?
This blog entry will look at three main ways of getting data. The first will be using the readBy methods. The second method will look at listBy. Lastly, I will talk about TQL and how it can be used for powerful searches.
Our first topic then is the set of readBy methods. This includes:
- readByProperty: Allows you to specify a property and value to search by.
- readByPropertyMap: Allows you to specify a struct of key/values where they key is a property and the value is what you filter by.
- readByQuery: Uses TQL to get an object. I won't discuss this very much now as I'm not covering TQL till the third section of this blog entry.
Now the number one thing you need to remember about these functions is that they must return one TransferObject only. So you would not use them to filter by employees who are girls for example. If any of these methods end up with two or more results, you will get an error. In some ways this kind of limits their usefulness. You would need to ensure that you only search on the kinds of things that are guaranteed to return one row. Note - you can do filters that return no rows. If you do, you get a blank TransferObject for the object type you are searching.
One example that comes to mind is a user system where you've defined usernames as being unique. I've written plenty of applications where I do a "username to id" translator.
Let's give this a try. Imagine our employee directory also stored their system login username:
<property name="username" type="string" />
I quickly updated the edit form to support this and updated a few of my employees to have usernames. Now let's run a test to get me (I saved this in a new file, test_get.cfm, for those who download the code):
<cfset ray = application.transfer.readByProperty("employee", "username", "cfjedimaster")>
<cfdump var="#ray.getMemento()#">
The API is simple enough. Tell Transfer the class, the property, and the value. readByPropertyMap isn't that much different. Instead of passing one property and value you pass a structure. To be honest, I can't think of a business case for this in my current application. For testing I'm going to just use username and last name. Since username is already unique this will work. But note that I don't think this is a great example:
<cfset s = {lastname="Camden",username="cfjedimaster"}>
<cfset ray = application.transfer.readByPropertyMap("employee", s)>
<cfdump var="#ray.getMemento()#">
Nothing too complex here. I made a quick struct and passed it to readByPropertyMap. You can have any number of keys and all must match in order for an object to be returned. Before we move on to the listBy methods, don't forget Transfer also has a readByQuery that will perform a TQL based seach. More on that later.
So while the readBy methods were useful for finding one particular object, the listBy methods can return a list of objects (in query form of course). These methods share a similar API with the readBy set:
- listByProperty: Let's you list all entries that match a property value.
- listByPropertyMap: Let's you list all entries that match a set of values defined in a structure.
- listByQuery: Again, this is a TQL version that we will look at later.
So let's start with a simple example. I'm going to add yet another property to my Employee object:
<property name="gender" type="string" />
I added the column to my database and again edited my form to allow for specifying a gender value of M or F. Now lets grab the boys and girls:
<cfset girls = application.transfer.listByProperty("employee", "gender", "F")>
<cfdump var="#girls#">
<cfset boys = application.transfer.listByProperty("employee", "gender", "M")>
<cfdump var="#boys#">
You can futher enhance the result by sorting:
<cfset girls = application.transfer.listByProperty("employee", "gender", "F", "lastname")>
<cfdump var="#girls#">
Or...
<cfset girls = application.transfer.listByProperty("employee", "gender", "F", "lastname","false")>
<cfdump var="#girls#">
This will sort by last name, descending. The listByPropertyMap works pretty much the exact same way as readByPropertyMap but with the option to also specify a sort column.
Alright - so if you played around with the code a bit you may have noticed something. All of these methods expect exact matches. You can't use them to search but rather to perform exact matches on properties. How would you do random, fuzzy (ie, partial matches) in Transfer? TQL (Transfer Query Language) is your solution. Until next time...
Archived Comments
Great stuff again! The sort by always gets me though. I always end up typing "asc" or "desc". I am still quite sure why its setup the way it is, but I will just have to burn it into my brain or change some source!
Kudos again! I'm champing at the bit to create the same thing for my admin crud for the current application. Going to do that and then try converting from FuseBox AllOverThePlace to FuseBox MVC, then maybe... ColdBox!
Like always, cool Tutorial! But do you know how to get just some Records like: "SELECT TOP 5 FROM Comments ORDER BY posted". So i do not have to get all Datas, but just the last/first 5 Records?
As far as I know, that isn't supported.
*hm*, but how should i do thinks like that within Transfer? I does not make sense to get all of the Datas first and then filterin them somehow?! And i also do not think that i'm the only one who hade the same issue? Google was not telling my anything as well :-(
Unfortunately TOP N is not currently supported in Transfer, however it is on the upcoming feature list.
It has been something that people have requested for a long time.
That all being said - very happy to take community contributions of features!
Hi Mark
i looked at the since the last view hours, so i'm quit shure that it is not supported ;-( But how can i get the 5 last comments then? No Way? Do you have a timeline when it will be supported?
Why not just use some regular ol' SQL ;)