So in my last post I was able to get some pretty awesome feedback on some questions I had. I am not going to go over everything about the post so please check it out first and read through the comments. In the end I wanted to find out how I could abstract commons functionality of the persistence layer in my application. What I am starting with here is by no means the *right* answer or my final, just my first stab.

I am going to use the cfbookclub datasource that ships with ColdFusion 9 so you can follow along at home. First we need to setup our application. This is my basic directory structure for the application and below is my Application component.


Nothing special going on so far. I want to keep this example simple so I will not be using any frameworks. You will notice that in my application start method I am creating 2 static objects, we will get to that in a minute. First we need to setup our entities and for this example we will only be using the Author and book objects. In the domain folder I am going to create an author and book cfc's. Each of these components should look pretty familiar. We do define a relationship between the two as well. In a more complex example down the road we will get into the use of an abstract domain but for now we will keep it simple.

Now we have our entities ready to get we can get started on our persistence layer. In the dao folder I am going to create an AbstractDAO component. To keep it simple we are going to start out by defining only a few methods.

  • New - I will create a new instance of the domain object.
  • Load - I will load an existing object from a database based on the primary key.
  • List - I will give you back a query of all the rows for this domain object.
  • FindBy - I am a dynamic finder that allows you to find exact matches dynamically (findByFirstAndLast("Dan","Vega"))
  • Save
  • Delete
First we will setup the base of the component. Now I want this component to always be extended, never instantiated. To make sure of this we can throw an error if it this ever happens. Next we will create the new method. With this comes our first problem. Notice how I had to hard code the entity that we are working with. If we truly want to make this universal that this is not going to work.

After a couple different attempts and some suggestions from others I finally came up with the following. First we are going to create our Author DAO component that extends the abstract dao object. Next we are going to add a little helper method for getting the entity name. We will use this method for almost every method in our abstract dao. This method is a pretty great way of figuring out what entity we are working with. You can either add a entity attribute to the component and it will read that or you can follow a naming convention. In our case we are working with the Author entity so i named it AuthorDAO. Now with my get entity in place our method becomes much more dynamic. Now we have the foundation and we can start building out our methods. Next up I am going to create a load method that accepts an id. If no id is passed then we will return a new object. Next we can create our list method. I don't know about you but when I think of listing rows from a database I think query. My list method will by default always return a query object. You can pass asquery = false to get an array of objects. At a later time we will look at different ways to pass more criteria to this method but for now we will keep it simple. Our save and delete methods are pretty straight forward. Which brings me to my favorite method, the findByDynamically. This was inspired by grails and a post I found by Joe Rinehart. This allows us to dynamically find any methods. For example our authors table has a firstname and lastname property. Using this method we could make the following method call and it would return us the record. The other "dynamic" feature I want to use in this method is the ability to return a query. When your searching for multiple fields your most likely going to bring back 1 record. In another scenario like the following I am going to get back many records, so it makes more sense to return a query. That's right, to get a query back just append asquery (case does not matter). To accomplish this we are going to use the onMissingMethod function. First we check to see if we are returning the result as a query. Next if the first 6 characters of the name is findby we can assume its probably something like findByXYZ or findByXAndY. The findByDynamically method is now called and works its magic. There are a couple of other private methods that you can check out in the download that help build our where clause but they are explained pretty well so check out the attached source code.

Complete AbstactDAO component.

In closing I could of went into way more depth here but I wanted to start out with some simple examples. Please download the attached demo and check out the code. I have many other methods in my abstract dao and I will share those soon. For now I would love your feedback / suggestions.