Page 1 of 2
Object Relational Mapping
Posted: Thu May 10, 2007 11:27 pm
by chris12295
What are some good tips to designing an ORM class? Specifically, is it more efficient for the object to represent a row in a table or the whole table?
Posted: Thu May 10, 2007 11:53 pm
by Christopher
Typically the mapping would be between an object and a row or related rows from several tables.
Posted: Fri May 11, 2007 2:00 am
by chris12295
So by mapping rows wouldn't the queries to the database be inefficient if you need several user's info? For example if the object maps to a row then each user would require a seperate database query
Posted: Fri May 11, 2007 2:40 am
by Chris Corbyn
chris12295 wrote:So by mapping rows wouldn't the queries to the database be inefficient if you need several user's info? For example if the object maps to a row then each user would require a seperate database query
Not really no. What usually happens is that all rows are pulled out as normal, then objects are hydrated with the values from the resultset before finally being returned as an array. If a single object represents a row it makes it easier to create new rows simply by creating new objects. It's a nicer interface.
Code: Select all
$user = new User();
$user->setUsername("foo");
$user->setPassword(md5("xxxxx"));
$user->save();
echo $user->getId();
It also makes it easy to join records at an object level:
Code: Select all
$thread = new Thread();
$thread->setTitle("foobar");
$thread->save();
$forumPost->setThread($thread);
$forumPost->save();
You may want to look at ActiveRecord too.
Posted: Fri May 11, 2007 2:51 am
by Kieran Huggins
Also check out Maugrim's awesome article on PHP data objects - just brilliant.
viewtopic.php?t=48499
Posted: Fri May 11, 2007 4:04 am
by wei
Here is an implementation of active record, table gate, and a data mapper. The data mapper is a good supplement to active records when the query get very complex, while active records are great for simple data access.
Docs and an example using the Northwind sample database (sqlite) are included. Requires php 5.1+ and the specific pdo database drivers.
http://xlab6.com/compact-db.zip
Wei.
Posted: Fri May 11, 2007 4:45 pm
by Z3RO21
Kieran Huggins wrote:Also check out Maugrim's awesome article on PHP data objects - just brilliant.
viewtopic.php?t=48499
Kieran beat me to it, but he is absolutely right. That tutorial is a very in depth tutorial. It helped me understand and implement object relational mapping.
Posted: Sat May 12, 2007 5:55 am
by mikesmith76
Hi all,
Sorry to hijack someone else's thread but I have a question about this topic. I've read Maugrim's tutorial and like the others found it to be an excellent read. However one part of it just doesn't feel right
Sticking with the example of a user, each object should contain the data for a single user. We would add / edit / delete a user by interacting with an object containing that user's data.
Copied from Maugrim's Tutorial
Code: Select all
<?php
$user = new User();
$user->setName('Maugrim');
$user->setEmail('email@example.com');
$user->setWww('http://blog.quantum-star.com');
$user->save(); // insert data on database table
?>
This is all great, but how about pulling multiple users at once. From the same tutorial Maugrim showed the following example
Code: Select all
<?php
$user_collection = new User();
$user_collection->getAll();
echo '<strong>List of User Names</strong><br /><br />';
foreach($user_collection as $key=>$user)
{
echo $user->getName(), '<br />';
}
?>
So here we are using an object designed to hold a single user's information to build an array of users? This is the part that doesn't look or feel right to me. The tutorial did mention this is just meant as a brief example. The approach I am leaning towards at the moment would be using a UserCollection object as in
Code: Select all
$user_collection = new UserCollection();
$user_collection->getAll();
//then using iterator type logic
while($user_collection->hasNext()){
//$user now contains an object of type User
$user = $user_collection->getNext();
}
Am I on the right lines with this? Please don't take this as an attack against Maugrim, his tutorial is excellent and his knowledge is much greater than mine. I'm just trying to adapt his tutorial to how I like to see things organised.
Thanks all
Mike
Posted: Sat May 12, 2007 6:47 am
by Chris Corbyn
Propel would do this:
Code: Select all
//Search criteria
$criteria = new Criteria();
$users = User::doSelect($criteria);
Using static methods as factories for objects which are an instance of the class they come from feels natural, so on that token, returning a collection of objects of that type seems logical too.
Of course, using Criteria like this means you can be smart about what you want:
Code: Select all
$criteria = new Criteria();
$criteria->add(User::GROUP, "moderator");
$users = User::doSelect($criteria); //all moderators
You can join tables with Criteria too, so because the above table probably isn't normalized, once normalized you'd have something like this.
Code: Select all
$criteria = new Criteria();
$criteria->addJoin(User::GROUP_ID, UserGroup::ID);
$criteria->add(UserGroup::TITLE, "moderator");
$users = User::doSelect($criteria); //all moderators
Posted: Sat May 12, 2007 7:09 am
by wei
I think either approach is fine and both have trade-offs. Using collections, you may be able to construct a query that performs a batch insert and/or update (although you may that tricky if the table contains sequences and they need to be retrieved). Combining the fetching of collections in to the Record class is reasonable approach in simplifying the design.
Posted: Sat May 12, 2007 7:14 am
by mikesmith76
Thanks for the reply, just found the Propel website so much more reading to go.
The main problem I'm having at the moment is i've never seen a large scale OOP application built in PHP, or any language for that matter. I'm just guessing as to how things like a collection of users should be organised, trying to educate my guesses with lots of reading!
I'm looking into ORM at the moment as I love the idea of being able to insert database records just by manipulating an object / set of objects. The code looks so much cleaner than having SQL statements littered around the place, and I imagine it will be much easier to maintain.
Thanks again
Mike
Posted: Sat May 12, 2007 7:27 am
by Chris Corbyn
mikesmith76 wrote:I'm looking into ORM at the moment as I love the idea of being able to insert database records just by manipulating an object / set of objects. The code looks so much cleaner than having SQL statements littered around the place, and I imagine it will be much easier to maintain.
There are some things that ORM simply isn't going to do for you (complex SQL queries which don't actually select records). I think the main objective of ORM is to overcome the issue of working with a database in a fully object-oriented environment. ORM *usually* happens on top of an abstraction layer which cleans and optimizes the SQL too as you have seen. This inveitably makes it much easier turn around in 3 years time and say "ditch mysql, we're going to Oracle".
EDIT | Actually, I have to say one of the other big benefits of ORM is when working with MVC it's really easy to get Model data *cleanly* into the view.
Hmmm, I only only just noticed by Propel have stopped using Creole (their own abstracton layer) and implemented PDO instead.
Posted: Sat May 12, 2007 8:16 am
by mikesmith76
Thanks for all the advice. I don't expect ORM to be a magical quick fix but definitely think it will be a useful tool.
You've mentioned Propel quite a few times so far, is this something you have a lot of experience with?
Posted: Sat May 12, 2007 8:59 am
by Chris Corbyn
mikesmith76 wrote:You've mentioned Propel quite a few times so far, is this something you have a lot of experience with?
I have a little experience with it from working with the symfony framework. It's PHP5-only though. It seems to be held in pretty high regard.
Posted: Sat May 12, 2007 3:30 pm
by Christopher
I built a really simple Data Mapper example for an O/RM thread a while back. It was just to show the idea and never finished -- as I recall it still needed Unit of Work implemented. The code was posted here:
viewtopic.php?p=342096#342096