活动记录(Active Record):一个对象,它包装数据库表或视图中某一行,封装数据库访问,并在这些数据上增加了领域逻辑。
对象既有数据又有行为。活动记录使用直截了当的方法,把数据访问逻辑置于领域对象中。
?
二、实现简单活动记录
活动记录在php许多框架中都有应用,如cakephp。
class="php" name="code"><?php /** * 行数据入口类 */ class OrderGateway { /*定义元数据映射*/ private $_name; private $_id; public function __construct($id, $name) { $this->setId($id); $this->setName($name); } public function getName() { return $this->_name; } public function setName($name) { $this->_name = $name; } public function getId() { return $this->_id; } public function setId($id) { $this->_id = $id; } /** * 入口类自身拥有更新操作 */ public function update() { $data = array('id' => $this->_id, 'name' => $this->_name); $sql = "UPDATE order SET "; foreach ($data as $field => $value) { $sql .= "`" . $field . "` = '" . $value . "',"; } $sql = substr($sql, 0, -1); $sql .= " WHERE id = " . $this->_id; return DB::query($sql); } /** * 入口类自身拥有插入操作 */ public function insert() { $data = array('name' => $this->_name); $sql = "INSERT INTO order "; $sql .= "(`" . implode("`,`", array_keys($data)) . "`)"; $sql .= " VALUES('" . implode("','", array_values($data)) . "')"; return DB::query($sql); } public static function load($rs) { /* 此处可加上缓存 */ return new OrderGateway($rs['id'] ? $rs['id'] : NULL, $rs['name']); } } /** * 上面内容与行数据入口一样 * 此类为领域逻辑,这里新建个类,不采用static */ class OrderAccess { public function find($id) { $sql = "SELECT * FROM order WHERE id = " . $id; $rs = DB::query($sql); return OrderGateway::load($rs);//这里返回的行对象 } public function insert($data){ OrderGateway::load($data)->insert(); } public function updateName($id,$name){ $rs = array('id' => $id,'name' => $name); OrderGateway::load($rs)->update(); } public function findAll() { $sql = "SELECT * FROM order"; $rs = DB::query($sql); $result = array(); if (is_array($rs)) { foreach ($rs as $row) { $result[] = OrderGateway::load($row); } } return $result; } } class DB { /** * 这只是一个执行SQL的演示方法 * @param string $sql 需要执行的SQL */ public static function query($sql) { echo "执行SQL: ", $sql, " <br />"; } } /** * 客户端调用 */ class Client { public static function main() { header("Content-type:text/html; charset=utf-8"); $access = new OrderAccess(); $order = $access->find(1); echo $order->getName(); $access->insert(array('name' => 'xxxxx')); $access->update(1,'xxxxx'); } } Client::main(); ?>
?
三、运行机制
●活动记录的本质是一个领域模型,每条活动记录负责向数据库保存数据,从数据库加载数据以及处理作用于数据之上的领域逻辑。
?
●此模式没有隐藏关系数据库的存在这个事实,因此通常使用此模式的同时几乎不用其他对象关系映射模式。
?
●活动记录和行数据入口十分相似,之前也多次提及。行数据入口仅有数据库访问而活动记录既有数据源逻辑又有领域逻辑。
?
●由于活动记录和数据库间的紧耦合,在这个模式中常用静态查找方法(例子采用的是新建类,这样更便于测试)。
?
●活动记录通常具有如下方法:
1、由SQL结果集中的一行构造一个活动记录实例(例中的OrderAccess->find方法
2、为将来对表的插入构造一个新的实例
3、用静态查找方法来包装常用的SQL查询和返回活动记录(例子采用新建类)
4、更新数据库并将活动记录中的数据插入数据库(例中的OrderAccess->update方法)
5、获取和设置域(例中的OrderGateway getName setName方法)
6、实现部分业务逻辑
?
四、使用场景?
1、领域模型
活动记录适用于不太复杂的领域逻辑,如CRRD等。仅当活动记录对象和数据库中表直接对应,才比较有效。如果业务逻辑复杂,就会想到使用对象的直接关系、集合和继承等。它们都难以映射到活动记录。
?
2、事务脚本
活动记录可以减少事务脚本代码重复的痛苦。
?
3、表模块(不考虑)
?
?
?