tags:

views:

105

answers:

1

This might be something very trivial, but I am a novice with some Object-Oriented patterns.

Put simply, is it a bad practice to use methods from one DAO in another DAO? I am trying to create an entity within a DAO and find it very hard to create that entity using just that DAO. So, is it ok to use other DAO methods within the other DAO?

Example:

public function readAllUsers() {
    $sql = "SELECT * FROM user";
    return $this->execute($sql);
}

public function execute($sql) {
$result = mysql_query($sql, $this->getDBConnection())
                or die(mysql_error());
    $user = array();
    if(mysql_num_rows($result) > 0) {
        for($i = 0; $i < mysql_num_rows($result); $i++) {
            $row = mysql_fetch_assoc($result);
            $user[$i]->setUsername(row["userName"]);
             ...set user info...
            $user[$i]->setAddresses($addressDAO->readAddressByUserId($userId));
        }
    }
    return $user;
}

NOTE: There are a good bit of attributes like this in the user entity that have a one-to-many relationship with the entity itself (addresses, emails, phone numbers, etc.). The query that would be needed (with all the linking tables that are used) would be tremendously complex.

Thanks,

Steve

+1  A: 

No, I wouldn't do it that way at all.

Sounds like you want to model a one-to-many relationship, so your hope is to use the inner DAO to get the many objects and then map them into the one.

Resist that temptation.

Your code tells you why:

  1. The outer loop brings back N objects with a one-to-many relationship.
  2. The inner loop queries once for each of the N objects and brings back its dependencies.

Classic noob N+1 query error. The network latency will kill you for large N.

The right thing to do is to do one query that brings back all your data at once and map it into the object(s) in question.

Maybe an ORM tool like Hibernate would be a good fit. If you have lots of 1:m relationships, I'd bet Hibernate would do as good as or a better job of generating efficient SQL than you will.

duffymo
Can you explain a little bit as to why it is a bad thing to do?
stjowa
@duffymo: I think that is a pretty bold statement (pun intended). I don't suppose you mean to use this for all occasions, do you? I mean, in some occasions (with large one-to-many datasets) lazy loading might be more appropriate, no?
fireeyedboy
Lazy loading is a good reason to use a an ORM tool that supports it properly. I wouldn't want anybody to write such a thing from scratch. And when I say "all your data", I don't mean millions of rows that result in an out of memory error. You have to be smart about what you fetch. Google queries return millions of hits, but they dole them back to you 25 at a time. Someone writing a DAO should be equally judicious about what they bring out of persistence and into memory.
duffymo
@fireeyedboy - loved the pun. I apologize for not giving it the notice it deserved in my response.
duffymo
@duffymo: So, how would I go about getting many addresses for each user and map it back to the object with a query? On top of that, how would I do the same thing with multiple attributes that will have this one-many relationship - with one query? I have looked online, and only have found how to use a join with a junction table. But this is much more complicated. Is it bad to have multiple queries to construct an entity within a DAO?
stjowa
I'd do it with one query and pay the penalty of more bytes on the wire instead of network latency: "SELECT user-info, address-info...". Bring the user-info back multiple times because it's better than network latency. Map it in once and then just do the address info.
duffymo
Haha, glad you liked the pun duffymo. Are you sure ORM tools do what you propose though? Don't ORM tools simple only load data when it's needed too? Or do most ORM tools offer some (runtime) config to either load everything at once when fetching a Model or only fetch when for instance a getter is called? I'm not too familiar with ORM tools other than Zend's (pseudo ORM?) Table gateway pattern. It has the option to create custom statements to join data, but that is practically the same as creating the join queries yourself.
fireeyedboy
Yes, I'm sure. This is what Hibernate was born for. You can ask it to do eager or lazy fetching.
duffymo