Win a copy of hapi.js in Action this week in the HTML, CSS and JavaScript forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

What's the "best" approach when needed to get info from multiple DAOs?

 
Juan Chris
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'm developing a software to manage a fictitious Cable TV system. I have the models `Channel` and `Program`:





And I have DAO implementations in MySQL for both of them. The problem is that when I call findAll() that returns a ArrayList<Channel> I'm obligated to call ProgramMySQLDAO inside the method because to construct one Channel I need the list of programs, hence I need to get those programs from the `Schedule` DB where I have the relation channel_id, program_id. This is becoming out of control. If I follow this pattern my CustomerMySQLDAO will also need to call others DAO to get subscriptions, etc. How and where can I handle those kind of calls? The only one that doesn't need all those crazy calls is my ProgramMySQLDAO because it doesn't depend on anything, see below the code for it:

 
Junilu Lacar
Sheriff
Posts: 9338
96
Android Eclipse IDE IntelliJ IDE Java Linux Mac Scala Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'll just point you in a direction for now, then you can come back with specific questions later.  Search for loading a complex object graph. Pay attention to the ones that have references to Hibernate and JPA.
 
Juan Chris
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:I'll just point you in a direction for now, then you can come back with specific questions later.  Search for loading a complex object graph. Pay attention to the ones that have references to Hibernate and JPA.


I tried doing what you said but I'm not experienced enough to even know what Hibernate and JPA means. I'm just starting with Modeal + DAO. So, I advanced a little bit, I end up with the following method:



The problem is that I'm calling ProgramMySQLDAO inside my ChannelMySQLDAO , and I feel that this is a bad practice.
 
Junilu Lacar
Sheriff
Posts: 9338
96
Android Eclipse IDE IntelliJ IDE Java Linux Mac Scala Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Juan Chris wrote:... and I feel that this is a bad practice.

Well, I have to commend you for that. For someone who claims to not have that much experience, you seem to have the sense of "design smells" that only more experienced people have.

In my experience, creating those kinds of dependencies is usually a recipe for pain, which of course can lead to disaster. It's often better to introduce another layer, one that aggregates and routes object data from/to multiple DAOs. When the logic becomes too complex, an ORM framework like Hibernate usually helps by taking care of most of the heavy lifting and plumbing work and you're left to deal with the more abstract and high-level abstract design aspects.  While an ORM framework like Hibernate can introduce its own constraints and challenges, the cost of learning and using it is often outweighed by the benefits it gives you in terms of consistency, flexibility, and often even, performance.

You can learn more about the JPA here: https://docs.oracle.com/javaee/6/tutorial/doc/bnbpz.html

You shouldn't be intimidated by either Hibernate or JPA. Even if you don't know much about them or even intend to use them, you can still get some ideas for some of the approaches that they use to manage the complexities of loading complex object graphs.

If you're not sure what an object graph is, it's just the formal name given to what you have: an object that contains references to other objects that contain references to other objects that contain references ... and so on.  That entire web of related objects you have is what's called an object graph.
 
Carey Brown
Bartender
Posts: 2125
26
Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I don't see where you are capturing the relationship between Channel and Program. I assume that you have a one-to-many relationship in that a channel can have multiple programs. It's possible it is a many-to-many relationship but I can't tell from what you've told us. With one-to-many you could add a relationship table with a column for channel ID and another column for program ID. If it indeed a one-to-many relationship you could add another column to your program table to hold a channel ID.
 
Liutauras Vilda
Sheriff
Posts: 3048
126
BSD VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Off topic, one tip.

You have your constructors as below:
In such way you're risking to have an 'id' in illegal state in case of first constructor invocation. What you really need to do when you have multiple constructors, is, the longest constructor's parameters initialize explicitly, and use that constructor in other (shorter overloaded) constructors.

i.e.:
This way, you'd always have 'id' value in an intended state. Of course this case doesn't demonstrate such risk very well as 'id' would be 0 anyway, but I think you understand what I mean.
 
Junilu Lacar
Sheriff
Posts: 9338
96
Android Eclipse IDE IntelliJ IDE Java Linux Mac Scala Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Also unrelated to the main line of questioning but an important point nonetheless, you should prefer to program to interfaces rather than implementations.

Anywhere you declare a parameter or a variable as an ArrayList<whatever>, you should change it to List<whatever> instead. This gives you maximum flexibility in passing references to these objects around in your program. If you write too much code that's specific to the ArrayList implementation type, you'll have a huge cleanup job later when you finally figure out that it would have been better if you had declared them as List instead.
 
Dave Tolls
Ranch Hand
Posts: 2207
20
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Carey Brown wrote:With one-to-many you could add a relationship table with a column for channel ID and another column for program ID.


One to many doesn't need a mapping table.
That's for many to many relationships.
One to many just needs an id on the "many" side.

However, I suspect that many to many is what is needed here...at least based on the number of channels that show CSI on Freeview!

Liutauras Vilda wrote:Of course this case doesn't demonstrate such risk very well as 'id' would be 0 anyway, but I think you understand what I mean.


In this case the id should be null.
The constructor with no id represents an object that hasn't been persisted to the database and so has no id yet.
You'll see it left alone in most models for this reason, since setting it to null is a bit pointless.
 
Liutauras Vilda
Sheriff
Posts: 3048
126
BSD VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Dave Tolls wrote:In this case the id should be null.
The constructor with no id represents an object that hasn't been persisted to the database and so has no id yet.
You'll see it left alone in most models for this reason, since setting it to null is a bit pointless.

And if there were or would be a theoretical need of 3rd constructor, for that would look wonky and not so explicit:

That version for me is more readable and tells the intention about the default values in case arguments were not supplied:

But yeah, I didn't take context of the problem in this case, well, at least OP can know about the difference of designing constructors in one or another way, that might would matter in other case.
 
Dave Tolls
Ranch Hand
Posts: 2207
20
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It's why, for JPA models, you tend to only see no args constructors.
Everything is set via the setters.
 
Juan Chris
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for the tips guys, I'll be reading about it. One thing I see a lot of people using and recommending is the approach: Model + DAO + Service. Inside the Service is where I should be calling more than one DAOs to get information from different places, I believe that makes sense.
 
Junilu Lacar
Sheriff
Posts: 9338
96
Android Eclipse IDE IntelliJ IDE Java Linux Mac Scala Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Juan Chris wrote:Inside the Service is where I should be calling more than one DAOs to get information from different places, I believe that makes sense.

That's the extra layer I was telling you about.  Architecturally, it would look more like  Model <--> Service <--> DAO <--> Persistent Store (DB, etc.)
 
Juan Chris
Greenhorn
Posts: 8
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:
Juan Chris wrote:Inside the Service is where I should be calling more than one DAOs to get information from different places, I believe that makes sense.

That's the extra layer I was telling you about.  Architecturally, it would look more like  Model <--> Service <--> DAO <--> Persistent Store (DB, etc.)


First, what do you mean by this "<-->"?

Second, tell me if I'm wrong, but what I have in mind is:

- Model is just a skeleton that we use when we want to do a INSERT into the database or when we SELECT something from into. Of course, after we get our Model instance from the database we may use it as we please (using the methods defined in our Model class like `getName()`, `getBirthdate()`, etc) to do whatever our software needs.
- DAO interface have the methods header that must be implemented, `findAll()`, `findByCustomer(Customer customer)`, `findByWhatever(Whatever whatever)`, `insert(Whatever whatever)`, `update(Whatever whatever)`, `delete(Whatever whatever)`.
- DAO implementation is where we put the code that will talk to our data source, be it SQLite, MySQL, Oracle, XML, file, etc.
- Service is where we will have instances of one or more DAOImpl and use those to have Models to work with and do our business logic, e.g., we may use CustomerDAOImpl to retrieve some Customer and use TvPlanDAOImpl to retrive a TvPlan, do some `getId()` and store it into the table Subscription (two columns, FK customer_id and FK tvplan_id) using SubscriptionDAOImpl.

Is that right?
 
Carey Brown
Bartender
Posts: 2125
26
Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Juan Chris wrote:First, what do you mean by this "<-->"?

Bi-directional communication.
 
Junilu Lacar
Sheriff
Posts: 9338
96
Android Eclipse IDE IntelliJ IDE Java Linux Mac Scala Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Carey Brown wrote:
Juan Chris wrote:First, what do you mean by this "<-->"?

Bi-directional communication.

More or less. I was thinking more along the lines of dependencies but communication is close enough  

Actually, now that you point that out, I guess it really should be a one way arrow from Service/DAO --> Model

You don't want your model to have a strong dependency on a Service or DAO. Domain objects should be fairly independent of infrastructure layer classes like DAO. Service classes kind of straddle the fence between the domain and infrastructure.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!