我们已经了解了怎样使用 Active Record (AR) 从单个数据表中获取数据。 在本节中,我们讲解怎样使用 AR 连接多个相关数据表并取回关联(join)后的数据集。
为了使用关系型 AR,我们建议在需要关联的表中定义主键-外键约束。这些约束可以帮助保证相关数据的一致性和完整性。
本例通过修改Yii Framework 开发教程(25) 数据库-Query Builder示例来介绍多个有关系的表如何使用Active Record。
在我们使用 AR 执行关联查询之前,我们需要让 AR 知道一个 AR 类是怎样关联到另一个的。
两个 AR 类之间的关系直接通过 AR 类所代表的数据表之间的关系相关联。 从数据库的角度来说,表 A 和 B 之间有三种关系:一对多(one-to-many,例如tbl_user
和tbl_post
),一对一( one-to-one 例如tbl_user
和tbl_profile
)和 多对多(many-to-many 例如tbl_category
和tbl_post
)。 在 AR 中,有四种关系:
BELONGS_TO
(属于): 如果表 A 和 B 之间的关系是一对多,则 表 B 属于 表 A (例如Post
属于User
);HAS_MANY
(有多个): 如果表 A 和 B 之间的关系是一对多,则 A 有多个 B (例如User
有多个Post
);HAS_ONE
(有一个): 这是HAS_MANY
的一个特例,A 最多有一个 B (例如User
最多有一个Profile
);MANY_MANY
: 这个对应于数据库中的 多对多 关系。 由于多数 DBMS 不直接支持 多对多 关系,因此需要有一个关联表将 多对多 关系分割为 一对多 关系。 在我们的示例数据结构中,tbl_post_category
就是用于此目的的。在 AR 术语中,我们可以解释MANY_MANY
为BELONGS_TO
和HAS_MANY
的组合。 例如,Post
属于多个(belongs to many)Category
,Category
有多个(has many)Post
.AR 中定义关系需要覆盖CActiveRecord中的relations()方法。此方法返回一个关系配置数组。每个数组元素通过如下格式表示一个单一的关系。
在Query Builder中我们使用了下面SQL查询语句
SELECT c.FirstName, c.LastName , c.Address,c.Email FROM customer c INNER JOIN employee e ON c.SupportRepId=e.EmployeeId WHERE e.EmployeeId=4
//Customer.php class Customer extends CActiveRecord { public static function model($className=__CLASS__) { return parent::model($className); } public function tableName() { return 'Customer'; } } //Employee.php class Employee extends CActiveRecord { public static function model($className=__CLASS__) { return parent::model($className); } public function tableName() { return 'Employee'; } public function relations() { return array( 'customers'=>array(self::HAS_MANY, 'Customer', 'SupportRepId'), ); } }
public function actionIndex() { $employee=Employee::model()->findByPk(4); $this->render('index', array( 'model' => $employee->customers, )); }
$employee=Post::model()->with('customers')->findAll();
<?php foreach($model as $customer) { echo 'First Name:' . $customer->FirstName . '<br />'; echo 'Last Name:' . $customer->LastName . '<br />'; echo 'Address:' . $customer->Address . '<br />'; echo 'Email:' . $customer->Email . '<br />'; echo '---------------------- <br />'; } ?>
不同的数据对列名大小写处理方式不同,有的数据库区分大小写,保险起见,Customer的属性使用和列定义同样的大小写。
本例下载
本例介绍了关联Active Record的最基本的用法,其它功能和属性可以参见Yii中文文档,此外如果借助类似CodeSmith这样的工具,如果能够自动生成数据库定义的ActiveRecord代码,就可以大大减轻程序员的代码手工编写工作量。
此外,使用Active Record的便利是以性能为代价的,通常情况下使用Active Record与使用DAO读写数据库性能相比要差一个级别。下表为一个参考值,查找200个演员和1000部电影。
方法 | 内存使用(M) | 执行时间(秒) |
Active Record | 19.74 | 1.14109 |
Query Builder | 17.98 | 0.35732 |
DAO | 17.74 | 0.35038 |