In the spirit of what Joe Rinehart and a few others have been doing so far in this the "year of OO for CFers," I thought I'd share what I've been working through this week. Specifically I've been grappling with Data Access Objects (DAOs) and how best to use them when composition is involved with the objects. I've done this several times before but I'm using a rebuild of our CFUG site to dig deep and try and figure out the best way to handle this (I'll stop short of saying "the right way to handle this"). For example, let's say I have a Person bean and an Address bean, and the Person bean has an Address bean in it. What's the best way to handle this situation in the DAOs?
Let's focus on the create method specifically since it's the most messy. If we're dealing with a Person and an Address, let's assume we have a form on which a person enters their basic personal information (name, email, etc.) and also their address information. When they submit this form, on the backend we need to create a Person object and an Address object, populate them with the form data, and pass them to a DAO to run the create method. There are a few different scenarios I've mulled over, and I've come up with my preferred way of doing this, but I'd be curious to get your feedback.
Scenario One: Handle Person and Address Separately
Because these are separate objects and each have their own DAO, one way of handling this would be to handle the Person and Address objects separately. In other words, after the form submission, in whatever component is handling the logic of processing the form, populate a Person, populate an Address, then call personDAO.create(person) and addressDAO.create(address) in sequence.
This may seem like the simplest way to handle things, but there are a few issues that arise. First, there is a bit of chicken and egg stuff going on with the relationship between Person and Address on the RDBMS side. Since the person and address tables are separate and related through a key (address_id in the person table), the Person really should have an Address id before personDAO.create() gets called. So we could reverse the order of the calls above and call addressDAO.create() first, then grab the address id from the result of that call and put it in the Person object, then call personDAO.create().
This isn't necessarily a bad way to do things, and would certainly work in this situation, but what happens when you get into more complex scenarios with multiple instances of composition (which in my application is the case)? In some cases the relationships and chicken-and-egg stuff gets even more complex, so you end up making multiple calls to your DAOs (create first to get the ids needed, then update later to put the ids in the necessary spots). Also, in my opinion you end up really muddying up things in the component that's handling the logic of the form submission (which in Mach-II is done in the listeners). So in my mind I scratched this option off as not the way to go about doing things.
Scenario Two: Put Address in Person and Have Separate Queries in the PersonDAO
It doesn't take but a few lines of typing the code for this scenario to realize what the faulty logic here is. It may seem like a decent idea at first, and you can even put the person and address queries in a nice tidy transaction on the database side, but you end up completely duplicating the code that's in the Address DAO, which is a big, big, big no-no. I must admit in some cases for deletion I have done this, but delete queries are typically extremely simple and likely wouldn't change over time. Something like a create might change in the future (if you add a field, for example), so you'd end up having to maintain the create logic in two places. Clearly not the right solution.
Scenario Three: Leverage the Address DAO Within the Person DAO
We're using composition in our beans, so why not use composition of sorts (this isn't strictly composition, but bear with me ...) in our DAO as well? When we instantiate the Person DAO, why not just instantiate an Address DAO inside the Person DAO so we can call things that way? Then after the form submission we're instantiating the Person bean, the Address bean, putting the Address bean in the Person bean, and just calling personDAO.create(person).
At this point, after much pacing and pondering, this is what makes the most sense to me. That isn't to say there aren't downsides here as well, which is why I'm posting my thoughts to get some feedback from others on this. I've seen plenty of examples of Java code that do this, so I'm assuming it's not flat-out "wrong," it seems to work well, and I really like the fact that it keeps things self-contained by only necessitating one call to the Person DAO (even if behind the scenes the Person DAO is actually calling the create method of the Address DAO as well).
There are still some chicken-and-egg situations when you do things this way. Those are relatively unavoidable in any of these scenarios. But what this gains you is A) complete reuse of the DAO code (no duplication of code as in scenario 2 above), and B) it keeps the logic of the form processing component a lot cleaner because you're just instantiating some objects and passing a single object to its DAO for the create action.
So am I on the right track? Is there a fourth option I haven't considered? Should I find a new career? Let me know your thoughts.