你现在可以开始操作更多的finder方法,包括收集Bookmark实例的方法。
class BookmarkMapperTestCase extends BaseTestCase { // ... function testFindByGroup() { $mapper = new BookmarkMapper($this->conn); $this->addSeveralBookmarks($mapper); $this->assertIsA( $php_links = $mapper->findByGroup(‘php’) ,’array’); $this->assertEqual(3, count($php_links)); foreach($php_links as $link) { $this->assertIsA($link, ‘Bookmark’); } } } |
寻找特殊组的bookmarks 可以操作如下:
class BookmarkMapper { // ... public function findByGroup($group) { $rs = $this->conn->execute( ‘select * from bookmark where tag like ?’ ,array($group.’%’)); if ($rs) { $ret = array(); foreach($rs->getArray() as $row) { $ret[] = $this->createBookmarkFromRow($row); } return $ret; } } } |
ADOConnection::execute()方法返回的时一个ADOResultSet 对象。所以返回的结果有一个getArray() 方法来进行处理,返回的一个联合数组 (field => value)。数组包含了每一行的数据。
接着,这些数据行形成的数组传递给createBookmarkFromRow()方法进行处理并创建Bookmark类的实例。
怎么更新数据映射呢?更新的操作通用需要用到Bookmark和BookmarkMapper。确保bookmarks有没有更新最好的方法是使用BookmarkTestCase。测试数据库访问的部分则由测试BookmarkMapper的代码负责。
class BookmarkTestCase extends BaseTestCase { // ... function testSaveUpdatesDatabase() { $mapper = new BookmarkMapper($this->conn); $this->addSeveralBookmarks($mapper); $bookmark = $mapper->findById(1); $this->assertEqual( ‘http://blog.casey-sweat.us/’ ,$bookmark->getUrl()); $bookmark->setUrl( ‘http://blog.casey-sweat.us/wp-rss2.php’); $mapper->save($bookmark); $bookmark2 = $mapper->findById(1); $this->assertEqual( ‘http://blog.casey-sweat.us/wp-rss2.php’ ,$bookmark2->getUrl()); } } |
现在,save()方法通过INSERT把新的bookmards插入到数据库。但是,就像这个测试用例涵盖的一样,save()现在必须确定Bookmark参数是新的或者已经增加到数据库里面了。对于前者,INSERT就可以操作了;对于后者,就需要用UPDATE了。
就目前的情况,让我们重构下操作INSERT语句的代码(这个原来是涵盖在save()方法里面的),成为一个新的私有的方法,命名为insert()。
class BookmarkMapper { |
class BookmarkMapper { //... public function save($bookmark) { if ($bookmark->getId()) { $this->update($bookmark); } else { $this->insert($bookmark); } } } |
现在,你还需要一个update() 方法,它和insert()方法很类似。回想一下,insert()方法按照固定的模式来编写代码从属性到域名进行数据映射。那么对于update(),让我们用一个更加动态的方法,从bookmark.xml里面获得信息并进行更改。
class BookmarkMapper { |
最后,让我们看下“删除”的操作。我们为BookmarkMapper类写一个方法来接受一个Bookmark并把它从数据库删掉。
首先,写一个测试代码:
class BookmarkMapperTestCase extends BaseTestCase { // ... function testDelete() { $mapper = new BookmarkMapper($this->conn); $this->addSeveralBookmarks($mapper); $this->assertEqual(5, $this->countBookmarks()); $delete_me = $mapper->findById(3); $mapper->delete($delete_me); $this->assertEqual(4, $this->countBookmarks()); } function countBookmarks() { return $this->conn->getOne( ‘select count(1) from bookmark’); } } |
代码本身:
class BookmarkMapper { // ... public function delete($bookmark) { $this->conn->execute( ‘delete from bookmark where id = ?’ ,array((int)$bookmark->getId())); } } |
现在,你可以通过数据映射模式来完整第进行操作了。
如果你的域对象创建起来比较繁琐,你可能需要写一个BookmarkMapper::deleteById()方法,它不需要加载域对象就能删除数据。
总结
很明显,在数据库和域对象之间增加一个转换层会造成一定的复杂性。但是,这个复杂性可以给你的代码带来巨大的灵活性,因为你可以不管数据库的表结构自由地升级你的类。
另外,你还需要记住的是所有这些例子还只是一个非常简单的转换机制。如果你需要对这个简单的机制进行升级,你可以参考holy grail of ORM—ObjectRelational Mapping—那里面会进行详细的阐述。