- 1 第一个应用 Hello World
- 2 Yii Web 应用基础
- 3 为应用添加日志
- 4 Hangman 猜单词游戏实例
- 5 URL 管理
- 6 CComponent 组件
- 7 使用 CHtml 创建 Form
- 8 使用 FormModel
- 9 UI 组件 Widget 概述
- 10 UI 组件 自定义组件
- 11 UI 组件 ActiveForm 示例
- 12 UI 组件 ClipWidget 示例
- 13 UI 组件 ContentDecorator 示例
- 14 UI 组件 MaskedTextField 示例
- 15 UI 组件 MultiFileUpload 示例
- 16 UI 组件 StarRating 示例
- 17 UI 组件 TabView 示例
- 18 UI 组件 TextHighlighter 示例
- 19 UI 组件 TreeView 示例
- 20 UI 组件 Captcha 示例
- 21 UI 组件 自定义 Captcha 示例
- 22 UI 组件 Zii 组件简介
- 23 数据库-概述
- 24 数据库-DAO 示例
- 25 数据库-Query Builder 示例
- 26 数据库-Active Record 示例
- 27 数据库-关联 Active Record 示例
- 28 Data Provider 简介
- 29 Zii 组件-Menu 示例
- 30 Zii 组件-ListView 示例
- 31 Zii 组件-DetailView 示例
- 32 Zii 组件-GridView 示例
- 33 Zii 组件-Accordion 示例
- 34 Zii 组件-AutoComplete 示例
- 35 Zii 组件-Button 示例
- 36 Zii 组件-DatePicker 示例
- 37 Zii 组件-Dialog 示例
- 38 Zii 组件-ProgressBar 示例
- 39 Zii 组件-Slider 示例
- 40 Zii 组件-SliderInput 示例
- 41 Zii 组件-Tabs 示例
- 42 Zii 组件-Draggable 示例
- 43 Zii 组件-Droppable 示例
- 44 Zii 组件-Resizable 示例
- 45 Zii 组件-Selectable 示例
- 46 Zii 组件-Sortable 示例
- 47 主题 Theme 示例
- 48 多国语言示例
27 数据库-关联 Active Record 示例
我们已经了解了怎样使用 Active Record (AR) 从单个数据表中获取数据。 在本节中,我们讲解怎样使用 AR 连接多个相关数据表并取回关联(join)后的数据集。
为了使用关系型 AR,我们建议在需要关联的表中定义主键-外键约束。这些约束可以帮助保证相关数据的一致性和完整性。
本例通过修改 数据库-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
涉及到两个表格 Employee 和 Customer,Employee 和 Customer 之间是一对多的关系,也就是说一个员工可以负责多个客户。Employee 到 Customer 的关系为 HAS_MANY, Customer 到 Employee 的关系为 HAS_ONE。因此可以定义 Employee 和 Customer 如下:
//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'), ); } }
因为本例只使用到由 Employee 查询对应的 Customer,因此只为类定义了 relations 方法。对应的表和外键为 Customer 和 SupportRepId。
然后修改 SiteController 的 indexAction 方法:
public function actionIndex() { $employee=Employee::model()->findByPk(4); $this->render('index', array( 'model' => $employee->customers, )); }
AR 类中的关系定义为每个关系向类中隐式添加了一个属性。在一个关联查询执行后,相应的属性将将被以关联的 AR 实例填充。因此由 $employee->customers 可以查询到 Employee 对应的 Customers 记录。 执行关联查询最简单的方法是读取一个 AR 实例中的关联属性。如果此属性以前没有被访问过,则一个关联查询将被初始化,它将两个表关联并使用当前 AR 实例的主键过滤。 查询结果将以所关联 AR 类的实例的方式保存到属性中。这就是传说中的 懒惰式加载(lazy loading,也可译为延迟加载) 方式,例如,关联查询只在关联的对象首次被访问时执行。 本例使用的为延迟加载,延迟加载在某些情况下并不高效。如果我们想获取 N 个帖子的作者,使用这种延迟加载将会导致执行 N 个关联查询。 这种情况下,我们应该改为使用 渴求式加载(eager loading)方式。 渴求式加载方式会在获取主 AR 实例的同时获取关联的 AR 实例。 这是通过在使用 AR 中的 find 或 findAll 方法时配合使用 with 方法完成的。例如:
$employee=Post::model()->with('customers')->findAll();
最后修改一下显示结果的 View 的代码:
<?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 的属性使用和列定义同样的大小写。
图片 27.1 picture27.1
本例介绍了关联 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 |
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论