Update db-active-record.md

This commit is contained in:
cuiliang
2018-04-14 17:31:25 +08:00
committed by GitHub
parent b51b089dc3
commit a10cecec92

View File

@ -1,14 +1,14 @@
活动记录
=============
活动记录Active Record
======================
[Active Record](http://zh.wikipedia.org/wiki/Active_Record) (活动记录,以下简称 AR提供了一个面向对象的接口,
用以访问和操作数据库中的数据。一个 AR 类关联一张数据表
每个 AR 对象对应表中的一行,对象的属性(即 AR 的特性Attribute映射到数据行的对应列。
即一条活动记录AR 对象对应数据表的一行AR 对象的属性则映射该行的相应列
您可以直接以面向对象的方式来操纵数据表中的数据,
[Active Record](http://zh.wikipedia.org/wiki/Active_Record) 提供了一个面向对象的接口,
用以访问和操作数据库中的数据。Active Record 类与数据库表关联
Active Record 实例对应于该表的一行,
Active Record 实例的*属性*表示该行中特定列的值
您可以访问 Active Record 属性并调用 Active Record 方法来访问和操作存储在数据表中的数据,
而不用编写原始 SQL 语句。
例如,假定 `Customer` AR 类关联着 `customer` 表,
例如,假定 `Customer` Active Record 类关联着 `customer` 表,
且该类的 `name` 属性代表 `customer` 表的 `name` 列。
你可以写以下代码来哉 `customer` 表里插入一行新的记录:
@ -27,45 +27,45 @@ $db->createCommand('INSERT INTO `customer` (`name`) VALUES (:name)', [
])->execute();
```
下面是所有目前被 Yii 的 AR 功能所支持的数据库列表
Yii 为以下关系数据库提供 Active Record 支持
* MySQL 4.1 及以上: 通过 [[yii\db\ActiveRecord]] 支持
* MySQL 4.1 及以上通过 [[yii\db\ActiveRecord]] 支持
* PostgreSQL 7.3 及以上:通过 [[yii\db\ActiveRecord]] 支持
* SQLite 2 and 3: 通过 [[yii\db\ActiveRecord]] 支持
* SQLite 2 and 3通过 [[yii\db\ActiveRecord]] 支持
* Microsoft SQL Server 2008 及以上:通过 [[yii\db\ActiveRecord]] 支持
* Oracle: 通过 [[yii\db\ActiveRecord]] 支持
* Oracle通过 [[yii\db\ActiveRecord]] 支持
* CUBRID 9.3 及以上:通过 [[yii\db\ActiveRecord]] 支持 (提示, 由于 CUBRID PDO 扩展的 [bug](http://jira.cubrid.org/browse/APIS-658)
给变量加引用将不起作用,所以你得使用 CUBRID 9.3 客户端及服务端。
* Sphinx: 通过 [[yii\sphinx\ActiveRecord]] 支持, 依赖 `yii2-sphinx` 扩展
* ElasticSearch: 通过 [[yii\elasticsearch\ActiveRecord]] 支持, 依赖 `yii2-elasticsearch` 扩展
* Sphinx通过 [[yii\sphinx\ActiveRecord]] 支持, 依赖 `yii2-sphinx` 扩展
* ElasticSearch通过 [[yii\elasticsearch\ActiveRecord]] 支持, 依赖 `yii2-elasticsearch` 扩展
此外Yii 的 AR 功能还支持以下 NoSQL 数据库:
此外Yii 的 Active Record 功能还支持以下 NoSQL 数据库:
* Redis 2.6.12 及以上: 通过 [[yii\redis\ActiveRecord]] 支持, 依赖 `yii2-redis` 扩展
* MongoDB 1.3.0 及以上: 通过 [[yii\mongodb\ActiveRecord]] 支持, 依赖 `yii2-mongodb` 扩展
在本教程中,我们会主要描述对关系型数据库的 AR 用法。
然而,绝大多数的内容在 NoSQL 的 AR 里同样适用。
在本教程中,我们会主要描述对关系型数据库的 Active Record 用法。
然而,绝大多数的内容在 NoSQL 的 Active Record 里同样适用。
## 声明 AR 类 <span id="declaring-ar-classes"></span>
## 声明 Active Record 类Declaring Active Record Classes <span id="declaring-ar-classes"></span>
要想声明一个 AR 类,你需要定义几个类 继承 [[yii\db\ActiveRecord]].
要想声明一个 Active Record 类,你需要声明该类继承 [[yii\db\ActiveRecord]]
### 设置表的名称
### 设置表的名称Setting a table name
默认的,每个 AR 类关联各自的数据库表。
默认的,每个 Active Record 类关联各自的数据库表。
经过 [[yii\helpers\Inflector::camel2id()]] 处理,[[yii\db\ActiveRecord::tableName()|tableName()]] 方法默认返回的表名称是通过类名转换来得。
如果这个默认名称不正确,你得重写这个方法。
此外, [[yii\db\Connection::$tablePrefix|tablePrefix]] 表前缀也会起作用。 例如, 如果
[[yii\db\Connection::$tablePrefix|tablePrefix]] 表前缀是 `tbl_`, `Customer` 的类名将转换成 `tbl_customer` 表名, `OrderItem` 转换成 `tbl_order_item`.
此外,[[yii\db\Connection::$tablePrefix|tablePrefix]] 表前缀也会起作用。例如,如果
[[yii\db\Connection::$tablePrefix|tablePrefix]] 表前缀是 `tbl_``Customer` 的类名将转换成 `tbl_customer` 表名,`OrderItem` 转换成 `tbl_order_item`
如果你定义的表名是 `{{%TableName}}`, 百分比字符 `%` 会被替换成表前缀。
例如, `{{%post}}` 会变成 `{{tbl_post}}` 表名两边的括号会被 [SQL 查询引用](db-dao.md#quoting-table-and-column-names) 处理。
例如, `{{%post}}` 会变成 `{{tbl_post}}`。表名两边的括号会被 [SQL 查询引用](db-dao.md#quoting-table-and-column-names) 处理。
下面的例子中,我们给 `customer` 数据库表定义叫 `Customer` 的 AR 类。
下面的例子中,我们给 `customer` 数据库表定义叫 `Customer` 的 Active Record 类。
```php
namespace app\models;
@ -78,7 +78,7 @@ class Customer extends ActiveRecord
const STATUS_ACTIVE = 1;
/**
* @return string AR 类关联的数据库表名称
* @return string Active Record 类关联的数据库表名称
*/
public static function tableName()
{
@ -87,19 +87,19 @@ class Customer extends ActiveRecord
}
```
### 将 AR 称为模型吧
AR 实例称为 [模型](structure-models.md)。因此, 我们通常将 AR
### 将 Active Record 称为模型Active records are called "models"
Active Record 实例称为[模型](structure-models.md)。因此, 我们通常将 Active Record
放在 `app\models` 命名空间下(或者其他保存模型的命名空间)。
因为 AR [[yii\db\ActiveRecord]] 继承了模型 [[yii\base\Model]], 它就拥有所有 [模型](structure-models.md) 特性,
比如说属性attributes验规则rules数据序列化等等。
因为 [[yii\db\ActiveRecord]] 继承了模型 [[yii\base\Model]], 它就拥有所有[模型](structure-models.md)特性,
比如说属性attributes规则rules数据序列化data serialization,等等。
## 建立数据库连接 <span id="db-connection"></span>
## 建立数据库连接Connecting to Databases <span id="db-connection"></span>
活动记录 AR 默认使用 `db` [组件](structure-application-components.md)
活动记录 Active Record 默认使用 `db` [组件](structure-application-components.md)
作为连接器 [[yii\db\Connection|DB connection]] 访问和操作数据库数据。
基于 [数据库访问](db-dao.md) 中的解释,你可以在系统配置中
基于[数据库访问](db-dao.md)中的解释,你可以在系统配置中
这样配置 `db` 组件。
```php
@ -132,20 +132,20 @@ class Customer extends ActiveRecord
```
## 查询数据 <span id="querying-data"></span>
## 查询数据Querying Data <span id="querying-data"></span>
定义 AR 类后,你可以从相应的数据库表中查询数据。
定义 Active Record 类后,你可以从相应的数据库表中查询数据。
查询过程大致如下三个步骤:
1. 通过 [[yii\db\ActiveRecord::find()]] 方法创建一个新的查询生成器对象;
2. 使用 [查询生成器的构建方法](db-query-builder.md#building-queries) 来构建你的查询;
3. 调用 [查询生成器的查询方法](db-query-builder.md#query-methods) 来取出数据到 AR 实例中。
2. 使用[查询生成器的构建方法](db-query-builder.md#building-queries)来构建你的查询;
3. 调用[查询生成器的查询方法](db-query-builder.md#query-methods)来取出数据到 Active Record 实例中。
你瞅瞅, 是不是跟 [查询生成器](db-query-builder.md) 的步骤差不多。
正如你看到的,是不是跟[查询生成器](db-query-builder.md)的步骤差不多。
唯一有区别的地方在于你用 [[yii\db\ActiveRecord::find()]] 去获得一个新的查询生成器对象,这个对象是 [[yii\db\ActiveQuery]]
而不是使用 `new` 操作符创建一个查询生成器对象。
下面是一些子,介绍如何使用 AR 查询数据:
下面是一些子,介绍如何使用 Active Query 查询数据:
```php
// 返回 ID 为 123 的客户:
@ -177,22 +177,22 @@ $customers = Customer::find()
上述代码中,`$customer` 是个 `Customer` 对象,而 `$customers` 是个以 `Customer` 对象为元素的数组。
它们两都是以 `customer` 表中取回的数据结果集填充的。
> Tip: 由于 [[yii\db\ActiveQuery]] 继承 [[yii\db\Query]]你可以使用 [查询生成器](db-query-builder.md) 章节里所描述的所有查询方法。
> Tip: 由于 [[yii\db\ActiveQuery]] 继承 [[yii\db\Query]]
你可以使用 [Query Builder](db-query-builder.md) 章节里所描述的*所有*查询方法。
根据主键获取数据行是比较常见的操作,所以 Yii
提供了两个快捷方法:
- [[yii\db\ActiveRecord::findOne()]] 返回一个 AR 实例,填充于查询结果的第一行数据。
- [[yii\db\ActiveRecord::findAll()]]:返回一个 AR 实例的数据,填充于查询结果的全部数据。
- [[yii\db\ActiveRecord::findOne()]]:返回一个 Active Record 实例,填充于查询结果的第一行数据。
- [[yii\db\ActiveRecord::findAll()]]:返回一个 Active Record 实例的数据,填充于查询结果的全部数据。
这两个方法的传参格式如下:
- 标量值:这个值会当作主键去查询。
Yii 会通过读取数据库模式信息来识别主键列。
Yii 会通过读取数据库模式信息来识别主键列。
- 标量值的数组:这数组里的值都当作要查询的主键的值。
- 关联数组:键值是表的列名,元素值是相应的要查询的条件值。
可以到 [哈希格式](db-query-builder.md#hash-format) 查看更多信息。
可以到 [哈希格式](db-query-builder.md#hash-format) 查看更多信息。
如下代码描述如何使用这些方法:
@ -242,7 +242,7 @@ $customers = Customer::findAll([
生成的 SQL 语句中。如果你的查询会返回很多行的数据,
你明确的应该加上 `limit(1)` 来提高性能,比如 `Customer::find()->limit(1)->one()`
除了使用查询生成器的方法之外,你还可以书写原生的 SQL 语句来查询数据,并填充结果集到 AR 对象中。
除了使用查询生成器的方法之外,你还可以书写原生的 SQL 语句来查询数据,并填充结果集到 Active Record 对象中。
通过使用 [[yii\db\ActiveRecord::findBySql()]] 方法:
```php
@ -255,11 +255,11 @@ $customers = Customer::findBySql($sql, [':status' => Customer::STATUS_INACTIVE])
多余的查询方法都会被忽略。
## 访问数据 <span id="accessing-data"></span>
## 访问数据Accessing Data <span id="accessing-data"></span>
如上所述,从数据库返回的数据被填充到 AR 实例中,
查询结果的每一行对应于单个 AR 实例。
您可以通过 AR 实例的属性来访问列值,例如,
如上所述,从数据库返回的数据被填充到 Active Record 实例中,
查询结果的每一行对应于单个 Active Record 实例。
您可以通过 Active Record 实例的属性来访问列值,例如,
```php
// "id" 和 "email" 是 "customer" 表中的列名
@ -268,23 +268,23 @@ $id = $customer->id;
$email = $customer->email;
```
> Tip: AR 的属性以区分大小写的方式为相关联的表列命名的。
Yii 会自动为关联表的每一列定义 AR 中的一个属性。
> Tip: Active Record 的属性以区分大小写的方式为相关联的表列命名的。
Yii 会自动为关联表的每一列定义 Active Record 中的一个属性。
您不应该重新声明任何属性。
由于 AR 的属性以表的列名命名,可能你会发现你正在编写像这样的 PHP 代码 :
`$ customer-> first_name`,如果你的表的列名是使用下划线分隔的,那么属性名中的单词
由于 Active Record 的属性以表的列名命名,可能你会发现你正在编写像这样的 PHP 代码
`$ customer-> first_name`,如果你的表的列名是使用下划线分隔的,那么属性名中的单词
以这种方式命名。 如果您担心代码风格一致性的问题,那么你应当重命名相应的表列名
(例如使用骆驼拼写法)。
### 数据转换 <span id="data-transformation"></span>
### 数据转换Data Transformation <span id="data-transformation"></span>
常常遇到,要输入或显示的数据是一种格式,而要将其存储在数据库中是另一种格式。
例如,在数据库中,您将客户的生日存储为 UNIX 时间戳(虽然这不是一个很好的设计),
而在大多数情况下,你想以字符串 `'YYYY/MM/DD'` 的格式处理生日数据。
为了实现这一目标,您可以在 `Customer` 中定义 *数据转换* 方法
定义 AR 类如下:
定义 Active Record 类如下:
```php
class Customer extends ActiveRecord
@ -304,16 +304,16 @@ class Customer extends ActiveRecord
```
现在你的 PHP 代码中,你可以访问 `$ customer-> birthdayText`
来以 `'YYYY/MM/DD'` 的格式输入和显示客户生日,而不是访问`$ customer-> birthday`
来以 `'YYYY/MM/DD'` 的格式输入和显示客户生日,而不是访问 `$ customer-> birthday`
> Tip: 上述示例显示了以不同格式转换数据的通用方法。如果你正在使用
> 日期值,您可以使用 [DateValidator](tutorial-core-validators.md#date) 和 [[yii\jui\DatePicker|DatePicker]] 来操作,
> 这将更易用,更强大。
### 以数组形式获取数据 <span id="data-in-arrays"></span>
### 以数组形式获取数据Retrieving Data in Arrays <span id="data-in-arrays"></span>
通过 AR 对象获取数据十分方便灵活,与此同时,当你需要返回大量的数据的时候,
通过 Active Record 对象获取数据十分方便灵活,与此同时,当你需要返回大量的数据的时候,
这样的做法并不令人满意,因为这将导致大量内存占用。在这种情况下,您可以
在查询方法前调用 [[yii\db\ActiveQuery::asArray()|asArray()]] 方法,来获取 PHP 数组形式的结果:
@ -326,16 +326,16 @@ $customers = Customer::find()
```
> Tip: 虽然这种方法可以节省内存并提高性能,但它更靠近较低的 DB 抽象层
你将失去大部分的 AR 提供的功能。 一个非常重要的区别在于列值的数据类型。
当您在 AR 实例中返回数据时,列值将根据实际列类型,自动类型转换;
你将失去大部分的 Active Record 提供的功能。 一个非常重要的区别在于列值的数据类型。
当您在 Active Record 实例中返回数据时,列值将根据实际列类型,自动类型转换;
然而,当您以数组返回数据时,列值将为
字符串(因为它们是没有处理过的 PDO 的结果),不管它们的实际列是什么类型。
### 批量获取数据 <span id="data-in-batches"></span>
### 批量获取数据Retrieving Data in Batches <span id="data-in-batches"></span>
在 [查询生成器](db-query-builder.md) 中,我们已经解释说可以使用 *批处理查询* 来最小化你的内存使用,
每当从数据库查询大量数据。你可以在 AR 中使用同样的技巧。例如,
每当从数据库查询大量数据。你可以在 Active Record 中使用同样的技巧。例如,
```php
// 每次获取 10 条客户数据
@ -355,15 +355,15 @@ foreach (Customer::find()->with('orders')->each() as $customer) {
```
## 保存数据 <span id="inserting-updating-data"></span>
## 保存数据Saving Data <span id="inserting-updating-data"></span>
使用 AR (活动记录),您可以通过以下步骤轻松地将数据保存到数据库:
使用 Active Record,您可以通过以下步骤轻松地将数据保存到数据库:
1. 准备一个 AR 实例
2. 将新值赋给 AR 的属性
1. 准备一个 Active Record 实例
2. 将新值赋给 Active Record 的属性
3. 调用 [[yii\db\ActiveRecord::save()]] 保存数据到数据库中。
举个栗子,
例如,
```php
// 插入新记录
@ -378,12 +378,12 @@ $customer->email = 'james@newexample.com';
$customer->save();
```
[[yii\db\ActiveRecord::save()|save()]] 方法可能插入或者更新表的记录,这取决于 AR 实例的状态。
[[yii\db\ActiveRecord::save()|save()]] 方法可能插入或者更新表的记录,这取决于 Active Record 实例的状态。
如果实例通过 `new` 操作符实例化,调用 [[yii\db\ActiveRecord::save()|save()]] 方法将插入新记录;
如果实例是一个查询方法的结果,调用 [[yii\db\ActiveRecord::save()|save()]] 方法
将更新这个实例对应的表记录行。
你可以通过检查 AR 实例的 [[yii\db\ActiveRecord::isNewRecord|isNewRecord]] 属性值来区分这两个状态。
你可以通过检查 Active Record 实例的 [[yii\db\ActiveRecord::isNewRecord|isNewRecord]] 属性值来区分这两个状态。
此属性也被使用在 [[yii\db\ActiveRecord::save()|save()]] 方法内部,
代码如下:
@ -402,7 +402,7 @@ public function save($runValidation = true, $attributeNames = null)
方法来插入或更新一条记录。
### 数据验证 <span id="data-validation"></span>
### 数据验证Data Validation <span id="data-validation"></span>
因为 [[yii\db\ActiveRecord]] 继承于 [[yii\base\Model]],它共享相同的 [输入验证](input-validation.md) 功能。
你可以通过重写 [[yii\db\ActiveRecord::rules()|rules()]] 方法声明验证规则并执行,
@ -416,10 +416,10 @@ public function save($runValidation = true, $attributeNames = null)
你可以调用 `save(false)` 来跳过验证过程。
### 块赋值 <span id="massive-assignment"></span>
### 块赋值Massive Assignment <span id="massive-assignment"></span>
和普通的 [models](structure-models.md) 一样,你亦可以享受 AR 实例的 [块赋值](structure-models.md#massive-assignment) 特性。
使用此功能,您可以在单个 PHP 语句中,给 AR 实例的多个属性批量赋值,
和普通的 [models](structure-models.md) 一样,你亦可以享受 Active Record 实例的 [块赋值](structure-models.md#massive-assignment) 特性。
使用此功能,您可以在单个 PHP 语句中,给 Active Record 实例的多个属性批量赋值,
如下所示。 记住,只有 [安全属性](structure-models.md#safe-attributes) 才可以批量赋值。
```php
@ -435,7 +435,7 @@ $customer->save();
```
### 更新计数 <span id="updating-counters"></span>
### 更新计数Updating Counters <span id="updating-counters"></span>
在数据库表中增加或减少一个字段的值是个常见的任务。我们将这些列称为“计数列”。
您可以使用 [[yii\db\ActiveRecord::updateCounters()|updateCounters()]] 更新一个或多个计数列。
@ -448,39 +448,39 @@ $post = Post::findOne(100);
$post->updateCounters(['view_count' => 1]);
```
> 注:如果你使用 [[yii\db\ActiveRecord::save()]] 更新一个计数列,你最终将得到错误的结果,
> Note: 如果你使用 [[yii\db\ActiveRecord::save()]] 更新一个计数列,你最终将得到错误的结果,
因为可能发生这种情况,多个请求间并发读写同一个计数列。
### 脏属性 <span id="dirty-attributes"></span>
### 脏属性Dirty Attributes <span id="dirty-attributes"></span>
当您调用 [[yii\db\ActiveRecord::save()|save()]] 保存 AR 实例时,只有 *脏属性*
当您调用 [[yii\db\ActiveRecord::save()|save()]] 保存 Active Record 实例时,只有 *脏属性*
被保存。如果一个属性的值已被修改,则会被认为是 *脏*,因为它是从 DB 加载出来的或者
刚刚保存到 DB 。请注意,无论如何 AR 都会执行数据验证
刚刚保存到 DB 。请注意,无论如何 Active Record 都会执行数据验证
不管有没有脏属性。
AR 自动维护脏属性列表。 它保存所有属性的旧值,
Active Record 自动维护脏属性列表。 它保存所有属性的旧值,
并其与最新的属性值进行比较,就是酱紫个道理。你可以调用 [[yii\db\ActiveRecord::getDirtyAttributes()]]
获取当前的脏属性。你也可以调用 [[yii\db\ActiveRecord::getDirtyAttributes()]]
将属性显式标记为脏。
如果你有需要获取属性原先的值,你可以调用
[[yii\db\ActiveRecord::getOldAttributes()|getOldAttributes()]] 或者 [[yii\db\ActiveRecord::getOldAttribute()|getOldAttribute()]].
[[yii\db\ActiveRecord::getOldAttributes()|getOldAttributes()]] 或者 [[yii\db\ActiveRecord::getOldAttribute()|getOldAttribute()]]
> 注:属性新旧值的比较是用 `===` 操作符,所以一样的值但类型不同,
> 依然被认为是脏的。当模型从 HTML 表单接收用户输入时,通常会出现这种情况,
> 其中每个值都表示为一个字符串类型。
> 为了确保正确的类型,比如,整型需要用 [过滤验证器](input-validation.md#data-filtering)
> 为了确保正确的类型,比如,整型需要用[过滤验证器](input-validation.md#data-filtering)
> `['attributeName', 'filter', 'filter' => 'intval']`。其他 PHP 类型转换函数一样适用,像
> [intval()](http://php.net/manual/en/function.intval.php) [floatval()](http://php.net/manual/en/function.floatval.php)
> [boolval](http://php.net/manual/en/function.boolval.php) 等等
> [boolval](http://php.net/manual/en/function.boolval.php),等等
### 默认属性值 <span id="default-attribute-values"></span>
### 默认属性值Default Attribute Values <span id="default-attribute-values"></span>
某些表列可能在数据库中定义了默认值。有时,你可能想预先填充
具有这些默认值的 AR 实例的 Web 表单。 为了避免再次写入相同的默认值,
具有这些默认值的 Active Record 实例的 Web 表单。 为了避免再次写入相同的默认值,
您可以调用 [[yii\db\ActiveRecord::loadDefaultValues()|loadDefaultValues()]] 来填充 DB 定义的默认值
进入相应的 AR 属性:
进入相应的 Active Record 属性:
```php
$customer = new Customer();
@ -489,11 +489,11 @@ $customer->loadDefaultValues();
```
### 属性类型转换 <span id="attributes-typecasting"></span>
### 属性类型转换Attributes Typecasting <span id="attributes-typecasting"></span>
在查询结果填充 [[yii\db\ActiveRecord]] 活动记录时,将自动对其属性值执行类型转换,基于
在查询结果填充 [[yii\db\ActiveRecord]] 时,将自动对其属性值执行类型转换,基于
[数据库表模式](db-dao.md#database-schema) 中的信息。 这允许从数据表中获取数据,
声明为整型的,使用 PHP 整型填充 AR 实例布尔值boolean的也用布尔值填充 AR 实例,等等。
声明为整型的,使用 PHP 整型填充 ActiveRecord 实例布尔值boolean的也用布尔值填充等等。
但是,类型转换机制有几个限制:
* 浮点值不被转换,并且将被表示为字符串,否则它们可能会使精度降低。
@ -512,17 +512,17 @@ $customer->loadDefaultValues();
从2.0.14开始Yii ActiveRecord 支持了更多的复杂数据类型,例如 JSON 或多维数组。
#### MySQL 和 PostgreSQL 的 JSON 类型 in MySQL and PostgreSQL
(在 ActiveRecord 的)数据填充后,基于 JSON 标准解码规则,来自 JSON 列的值将自动解码。
#### MySQL 和 PostgreSQL 的 JSONJSON in MySQL and PostgreSQL
数据填充后,基于 JSON 标准解码规则,
来自 JSON 列的值将自动解码。
另一方面,为了将属性值保存到 JSON 列中ActiveRecord 会自动创建一个 [[yii\db\JsonExpression|JsonExpression]] 对象,
这对象将在 [QueryBuilder](db-query-builder.md) 层被编码成 JSON 字符串。
#### PostgreSQL 的数组类型
#### PostgreSQL 的数组Arrays in PostgreSQL
(在 ActiveRecord 的)数据填充后,来自 Array 列的值将自动从 PgSQL 的编码值解码为 一个 [[yii\db\ArrayExpression|ArrayExpression]]
数据填充后,来自 Array 列的值将自动从 PgSQL 的编码值解码为 一个 [[yii\db\ArrayExpression|ArrayExpression]]
对象。它继承于 PHP 的 `ArrayAccess` 接口,所以你可以把它当作一个数组用,或者调用 `->getValue()` 来获取数组本身。
另一方面为了将属性值保存到数组列ActiveRecord 会自动创建一个 [[yii\db\ArrayExpression|ArrayExpression]] 对象,
@ -534,12 +534,12 @@ $customer->loadDefaultValues();
$query->andWhere(['=', 'json', new ArrayExpression(['foo' => 'bar'])
```
要详细了解表达式构建系统,可以访问 [查询构建器 增加自定义条件和语句](db-query-builder.md#adding-custom-conditions-and-expressions)
要详细了解表达式构建系统,可以访问 [Query Builder 增加自定义条件和语句](db-query-builder.md#adding-custom-conditions-and-expressions)
文章。
### 更新多个数据行 <span id="updating-multiple-rows"></span>
### 更新多个数据行Updating Multiple Rows <span id="updating-multiple-rows"></span>
上述方法都可以用于单个 AR 实例,以插入或更新单条
上述方法都可以用于单个 Active Record 实例,以插入或更新单条
表数据行。 要同时更新多个数据行,你应该调用 [[yii\db\ActiveRecord::updateAll()|updateAll()]]
这是一个静态方法。
@ -557,9 +557,9 @@ Customer::updateAllCounters(['age' => 1]);
```
## 删除数据 <span id="deleting-data"></span>
## 删除数据Deleting Data <span id="deleting-data"></span>
要删除单行数据,首先获取与该行对应的 AR 实例,然后调用
要删除单行数据,首先获取与该行对应的 Active Record 实例,然后调用
[[yii\db\ActiveRecord::delete()]] 方法。
```php
@ -573,43 +573,43 @@ $customer->delete();
Customer::deleteAll(['status' => Customer::STATUS_INACTIVE]);
```
> Tip: 不要随意使用 [[yii\db\ActiveRecord::deleteAll()|deleteAll()]] 它真的会
清空你表里的数据,因为你指不定啥时候犯二
> Tip: 用 [[yii\db\ActiveRecord::deleteAll()|deleteAll()]] 时要非常小心,因为如果在指定条件时出错,
它可能会完全擦除表中的所有数据
## AR 的生命周期 <span id="ar-life-cycles"></span>
## Active Record 的生命周期Active Record Life Cycles <span id="ar-life-cycles"></span>
当你实现各种功能的时候,会发现了解 AR 的生命周期很重要。
当你实现各种功能的时候,会发现了解 Active Record 的生命周期很重要。
在每个生命周期中,一系列的方法将被调用执行,您可以重写这些方法
以定制你要的生命周期。您还可以响应触发某些 AR 事件
以便在生命周期中注入您的自定义代码。这些事件在开发 AR 的 [行为](concept-behaviors.md)时特别有用,
通过行为可以定制 AR 生命周期的 。
以定制你要的生命周期。您还可以响应触发某些 Active Record 事件
以便在生命周期中注入您的自定义代码。这些事件在开发 Active Record 的 [行为](concept-behaviors.md)时特别有用,
通过行为可以定制 Active Record 生命周期的 。
下面,我们将总结各种 AR 的生命周期,以及生命周期中
下面,我们将总结各种 Active Record 的生命周期,以及生命周期中
所涉及的各种方法、事件。
### 实例化生命周期 <span id="new-instance-life-cycle"></span>
### 实例化生命周期New Instance Life Cycle <span id="new-instance-life-cycle"></span>
当通过 `new` 操作符新建一个 AR 实例时,会发生以下生命周期:
当通过 `new` 操作符新建一个 Active Record 实例时,会发生以下生命周期:
1. 类的构造函数调用.
2. [[yii\db\ActiveRecord::init()|init()]]:触发 [[yii\db\ActiveRecord::EVENT_INIT|EVENT_INIT]] 事件。
### 查询数据生命周期 <span id="querying-data-life-cycle"></span>
### 查询数据生命周期Querying Data Life Cycle <span id="querying-data-life-cycle"></span>
当通过 [查询方法](#querying-data) 查询数据时,每个新填充出来的 AR 实例
当通过 [查询方法](#querying-data) 查询数据时,每个新填充出来的 Active Record 实例
将发生下面的生命周期:
1. 类的构造函数调用.
1. 类的构造函数调用
2. [[yii\db\ActiveRecord::init()|init()]]:触发 [[yii\db\ActiveRecord::EVENT_INIT|EVENT_INIT]] 事件。
3. [[yii\db\ActiveRecord::afterFind()|afterFind()]]:触发 [[yii\db\ActiveRecord::EVENT_AFTER_FIND|EVENT_AFTER_FIND]] 事件。
### 保存数据生命周期 <span id="saving-data-life-cycle"></span>
### 保存数据生命周期Saving Data Life Cycle <span id="saving-data-life-cycle"></span>
当通过 [[yii\db\ActiveRecord::save()|save()]] 插入或更新 AR 实例时
当通过 [[yii\db\ActiveRecord::save()|save()]] 插入或更新 Active Record 实例时
会发生以下生命周期:
1. [[yii\db\ActiveRecord::beforeValidate()|beforeValidate()]]:触发
@ -628,9 +628,9 @@ Customer::deleteAll(['status' => Customer::STATUS_INACTIVE]);
或者 [[yii\db\ActiveRecord::EVENT_AFTER_UPDATE|EVENT_AFTER_UPDATE]] 事件。
### 删除数据生命周期 <span id="deleting-data-life-cycle"></span>
### 删除数据生命周期Deleting Data Life Cycle <span id="deleting-data-life-cycle"></span>
当通过 [[yii\db\ActiveRecord::delete()|delete()]] 删除 AR 实例时,
当通过 [[yii\db\ActiveRecord::delete()|delete()]] 删除 Active Record 实例时,
会发生以下生命周期:
1. [[yii\db\ActiveRecord::beforeDelete()|beforeDelete()]]:触发
@ -642,24 +642,24 @@ Customer::deleteAll(['status' => Customer::STATUS_INACTIVE]);
> Tip: 调用以下方法则不会启动上述的任何生命周期,
> 因为这些方法直接操作数据库,而不是基于 AR 模型:
> 因为这些方法直接操作数据库,而不是基于 Active Record 模型:
>
> - [[yii\db\ActiveRecord::updateAll()]]
> - [[yii\db\ActiveRecord::deleteAll()]]
> - [[yii\db\ActiveRecord::updateCounters()]]
> - [[yii\db\ActiveRecord::updateAllCounters()]]
### 刷新数据生命周期 <span id="refreshing-data-life-cycle"></span>
### 刷新数据生命周期Refreshing Data Life Cycle <span id="refreshing-data-life-cycle"></span>
当通过 [[yii\db\ActiveRecord::refresh()|refresh()]] 刷新 AR 实例时,
当通过 [[yii\db\ActiveRecord::refresh()|refresh()]] 刷新 Active Record 实例时,
如刷新成功方法返回 `true`,那么 [[yii\db\ActiveRecord::EVENT_AFTER_REFRESH|EVENT_AFTER_REFRESH]] 事件将被触发。
## 事务操作 <span id="transactional-operations"></span>
## 事务操作Working with Transactions <span id="transactional-operations"></span>
AR 活动记录有两种方式来使用 [事务](db-dao.md#performing-transactions)。
Active Record 有两种方式来使用[事务](db-dao.md#performing-transactions)。
第一种方法是在事务块中显式地包含 AR 的各个方法调用,如下所示,
第一种方法是在事务块中显式地包含 Active Record 的各个方法调用,如下所示,
```php
$customer = Customer::findOne(123);
@ -723,7 +723,7 @@ class Customer extends ActiveRecord
这个事务方法的原理是:相应的事务在调用 [[yii\db\ActiveRecord::beforeSave()|beforeSave()]] 方法时开启,
在调用 [[yii\db\ActiveRecord::afterSave()|afterSave()]] 方法时被提交。
## 乐观锁 <span id="optimistic-locks"></span>
## 乐观锁Optimistic Locks <span id="optimistic-locks"></span>
乐观锁是一种防止此冲突的方法:一行数据
同时被多个用户更新。例如,同一时间内,用户 A 和用户 B 都在编辑
@ -739,15 +739,15 @@ class Customer extends ActiveRecord
使用乐观锁的步骤,
1. 在与 AR 类相关联的 DB 表中创建一个列,以存储每行的版本号。
1. 在与 Active Record 类相关联的 DB 表中创建一个列,以存储每行的版本号。
这个列应当是长整型(在 MySQL 中是 `BIGINT DEFAULT 0`)。
2. 重写 [[yii\db\ActiveRecord::optimisticLock()]] 方法返回这个列的命名。
3. 在用于用户填写的 Web 表单中添加一个隐藏字段hidden field来存储正在更新的行的当前版本号。
AR 类中)版本号这个属性你要自行写进 rules() 方法并自己验证一下。
4. 在使用 AR 更新数据的控制器动作中要捕获try/catch [[yii\db\StaleObjectException]] 异常。
Active Record 类中)版本号这个属性你要自行写进 rules() 方法并自己验证一下。
4. 在使用 Active Record 更新数据的控制器动作中要捕获try/catch [[yii\db\StaleObjectException]] 异常。
实现一些业务逻辑来解决冲突(例如合并更改,提示陈旧的数据等等)。
举个栗子,假定版本列被命名为 `version`。您可以使用下面的代码来实现乐观锁。
 
例如,假定版本列被命名为 `version`。您可以使用下面的代码来实现乐观锁。
```php
@ -782,18 +782,18 @@ public function actionUpdate($id)
```
## 使用关联数据 <span id="relational-data"></span>
## 使用关联数据Working with Relational Data <span id="relational-data"></span>
除了处理单个数据库表之外AR 还可以将相关数据集中进来,
除了处理单个数据库表之外Active Record 还可以将相关数据集中进来,
使其可以通过原始数据轻松访问。 例如,客户数据与订单数据相关
因为一个客户可能已经存放了一个或多个订单。这种关系通过适当的声明,
你可以使用 `$customer->orders` 表达式访问客户的订单信息
这表达式将返回包含 `Order` AR 实例的客户订单信息的数组。
这表达式将返回包含 `Order` Active Record 实例的客户订单信息的数组。
### 声明关联关系 <span id="declaring-relations"></span>
### 声明关联关系Declaring Relations <span id="declaring-relations"></span>
你必须先在 AR 类中定义关联关系,才能使用 AR 的关联数据。
你必须先在 Active Record 类中定义关联关系,才能使用 Active Record 的关联数据。
简单地为每个需要定义关联关系声明一个 *关联方法* 即可,如下所示,
```php
@ -829,12 +829,12 @@ class Order extends ActiveRecord
- 关联的对应关系:通过调用 [[yii\db\ActiveRecord::hasMany()|hasMany()]]
或者 [[yii\db\ActiveRecord::hasOne()|hasOne()]] 指定。在上面的例子中,您可以很容易看出这样的关联声明:
一个客户可以有很多订单,而每个订单只有一个客户。
- 相关联 AR 类名:用来指定为 [[yii\db\ActiveRecord::hasMany()|hasMany()]] 或者
- 相关联 Active Record 类名:用来指定为 [[yii\db\ActiveRecord::hasMany()|hasMany()]] 或者
[[yii\db\ActiveRecord::hasOne()|hasOne()]] 方法的第一个参数。
推荐的做法是调用 `Xyz::className()` 来获取类名称的字符串,以便您
可以使用 IDE 的自动补全,以及让编译阶段的错误检测生效。
- 两组数据的关联列用以指定两组数据相关的列hasOne()/hasMany() 的第二个参数)。
数组的值填的是主数据的列(当前要声明关联的 AR 类为主数据),
数组的值填的是主数据的列(当前要声明关联的 Active Record 类为主数据),
而数组的键要填的是相关数据的列。
一个简单的口诀,先附表的主键,后主表的主键。
@ -842,7 +842,7 @@ class Order extends ActiveRecord
译者注hasMany() 的第二个参数,这个数组键值顺序不要弄反了)
### 访问关联数据 <span id="accessing-relational-data"></span>
### 访问关联数据Accessing Relational Data <span id="accessing-relational-data"></span>
定义了关联关系后,你就可以通过关联名访问相应的关联数据了。就像
访问一个由关联方法定义的对象一样,具体概念请查看 [属性](concept-properties.md)。
@ -861,9 +861,9 @@ $orders = $customer->orders;
[属性](concept-properties.md) 那样访问 `xyz`。注意这个命名是区分大小写的。
如果使用 [[yii\db\ActiveRecord::hasMany()|hasMany()]] 声明关联关系,则访问此关联属性
将返回相关的 AR 实例的数组;
将返回相关的 Active Record 实例的数组
如果使用 [[yii\db\ActiveRecord::hasOne()|hasOne()]] 声明关联关系,访问此关联属性
将返回相关的 AR 实例,如果没有找到相关数据的话,则返回 `null`
将返回相关的 Active Record 实例,如果没有找到相关数据的话,则返回 `null`
当你第一次访问关联属性时,将执行 SQL 语句获取数据,如
上面的例子所示。如果再次访问相同的属性,将返回先前的结果,而不会重新执行
@ -873,7 +873,7 @@ SQL 语句。要强制重新执行 SQL 语句,你应该先 unset 这个关联
> Tip: 虽然这个概念跟 这个 [属性](concept-properties.md) 特性很像,
> 但是还是有一个很重要的区别。普通对象属性的属性值与其定义的 getter 方法的类型是相同的。
> 而关联方法返回的是一个 [[yii\db\ActiveQuery]] 活动查询生成器的实例。只有当访问关联属性的的时候,
> 才会返回 [[yii\db\ActiveRecord]] AR 实例,或者 AR 实例组成的数组。
> 才会返回 [[yii\db\ActiveRecord]] Active Record 实例,或者 Active Record 实例组成的数组。
>
> ```php
> $customer->orders; // 获得 `Order` 对象的数组
@ -883,7 +883,7 @@ SQL 语句。要强制重新执行 SQL 语句,你应该先 unset 这个关联
> 这对于创建自定义查询很有用,下一节将对此进行描述。
### 动态关联查询 <span id="dynamic-relational-query"></span>
### 动态关联查询Dynamic Relational Query <span id="dynamic-relational-query"></span>
由于关联方法返回 [[yii\db\ActiveQuery]] 的实例,因此你可以在执行 DB 查询之前,
使用查询构建方法进一步构建此查询。例如,
@ -927,10 +927,10 @@ $orders = $customer->bigOrders;
```
### 中间关联表 <span id="junction-table"></span>
### 中间关联表Relations via a Junction Table <span id="junction-table"></span>
在数据库建模中,当两个关联表之间的对应关系是多对多时,
通常会引入一个 [连接表](https://en.wikipedia.org/wiki/Junction_table)。例如,`order`
通常会引入一个[连接表](https://en.wikipedia.org/wiki/Junction_table)。例如,`order`
`item` 表可以通过名为 `order_item` 的连接表相关联。一个 order 将关联多个 order items
而一个 order item 也会关联到多个 orders。
@ -981,7 +981,7 @@ $items = $order->items;
```
### 通过多个(中间表)表来连接关联声明 <span id="multi-table-relations"></span>
### 通过多个表来连接关联声明Chaining relation definitions via multiple tables <span id="multi-table-relations"></span>
通过使用 [[yii\db\ActiveQuery::via()|via()]] 方法,它还可以通过多个表来定义关联声明。
再考虑考虑上面的例子,我们有 `Customer`, `Order`, 和 `Item` 类。
@ -1016,10 +1016,10 @@ class Customer extends ActiveRecord
```
### 延迟加载和即时加载(又称惰性加载与贪婪加载 <span id="lazy-eager-loading"></span>
### 延迟加载和即时加载(Lazy Loading and Eager Loading <span id="lazy-eager-loading"></span>
在 [访问关联数据](#accessing-relational-data) 中,我们解释说可以像问正常的对象属性那样
访问 AR 实例的关联属性。SQL 语句仅在
访问 Active Record 实例的关联属性。SQL 语句仅在
你第一次访问关联属性时执行。我们称这种关联数据访问方法为 *延迟加载*
例如,
@ -1034,7 +1034,7 @@ $orders = $customer->orders;
$orders2 = $customer->orders;
```
延迟加载使用非常方便。但是,当你需要访问相同的具有多个 AR 实例的关联属性时,
延迟加载使用非常方便。但是,当你需要访问相同的具有多个 Active Record 实例的关联属性时,
可能会遇到性能问题。请思考一下以下代码示例。
有多少 SQL 语句会被执行?
@ -1068,11 +1068,11 @@ foreach ($customers as $customer) {
}
```
通过调用 [[yii\db\ActiveQuery::with()]] 方法,你使 AR 在一条 SQL 语句里就返回了这 100 位客户的订单。
通过调用 [[yii\db\ActiveQuery::with()]] 方法,你使 Active Record 在一条 SQL 语句里就返回了这 100 位客户的订单。
结果就是,你把要执行的 SQL 语句从 101 减少到 2 条!
你可以即时加载一个或多个关联。 你甚至可以即时加载 *嵌套关联* 。嵌套关联是一种
在相关的 AR 类中声明的关联。例如,`Customer` 通过 `orders` 关联属性 与 `Order` 相关联,
在相关的 Active Record 类中声明的关联。例如,`Customer` 通过 `orders` 关联属性 与 `Order` 相关联,
`Order``Item` 通过 `items` 关联属性相关联。 当查询 `Customer` 时,您可以即时加载
通过嵌套关联符 `orders.items` 关联的 `items`
@ -1136,7 +1136,7 @@ $customers = Customer::find()->with([
> ```
### 关联关系的 JOIN 查询 <span id="joining-with-relations"></span>
### 关联关系的 JOIN 查询Joining with Relations <span id="joining-with-relations"></span>
> Tip: 这小节的内容仅仅适用于关系数据库,
比如 MySQLPostgreSQL 等等。
@ -1179,9 +1179,9 @@ $customers = Customer::find()
如果你想要的连接类型是 `INNER JOIN`,你可以直接用 [[yii\db\ActiveQuery::innerJoinWith()|innerJoinWith()]] 方法代替。
调用 [[yii\db\ActiveQuery::joinWith()|joinWith()]] 方法会默认 [即时加载](#lazy-eager-loading) 相应的关联数据。
如果你不需要那些关联数据,你可以指定它的第二个参数 $eagerLoading` 为 `false`。
如果你不需要那些关联数据,你可以指定它的第二个参数 `$eagerLoading``false`
> 提示:即使在启用即时加载的情况下使用 [[yii\db\ActiveQuery::joinWith()|joinWith()]] 或 [[yii\db\ActiveQuery::innerJoinWith()|innerJoinWith()]],相应的关联数据也**不会**从这个 `JOIN` 查询的结果中填充。 因此,每个连接关系还有一个额外的查询,正如 [即时加载](#lazy-eager-loading) 部分所述。
> Note: 即使在启用即时加载的情况下使用 [[yii\db\ActiveQuery::joinWith()|joinWith()]] 或 [[yii\db\ActiveQuery::innerJoinWith()|innerJoinWith()]],相应的关联数据也**不会**从这个 `JOIN` 查询的结果中填充。 因此,每个连接关系还有一个额外的查询,正如[即时加载](#lazy-eager-loading)部分所述。
和 [[yii\db\ActiveQuery::with()|with()]] 一样,你可以 join 多个关联表;你可以动态的自定义
你的关联查询;你可以使用嵌套关联进行 join。你也可以将 [[yii\db\ActiveQuery::with()|with()]]
@ -1212,14 +1212,14 @@ $customers = Customer::find()->joinWith([
```
以上查询取出 *所有* 客户,并为每个客户取回所有活跃订单。
港真,这与我们之前的例子不同,后者仅取出至少有一个活跃订单的客户。
请注意,这与我们之前的例子不同,后者仅取出至少有一个活跃订单的客户。
> Tip: 当通过 [[yii\db\ActiveQuery::onCondition()|onCondition()]] 修改 [[yii\db\ActiveQuery]] 时,
如果查询涉及到 JOIN 查询,那么条件将被放在 `ON` 部分。如果查询不涉及
JOIN ,条件将自动附加到查询的 `WHERE` 部分。
因此,它可以只包含 包含了关联表的列 的条件。(译者注:意思是 onCondition() 中可以只写关联表的列,主表的列写不写都行)
#### Relation table aliases <span id="relation-table-aliases"></span>
#### 关联表别名(Relation table aliases <span id="relation-table-aliases"></span>
如前所述,当在查询中使用 JOIN 时,我们需要消除列名的歧义。因此通常为一张表定义
一个别名。可以通过以下列方式自定义关联查询来设置关联查询的别名:
@ -1251,9 +1251,9 @@ $query->joinWith(['orders o' => function($q) {
->where('o.amount > 100');
```
### 反向关联 <span id="inverse-relations"></span>
### 反向关联Inverse Relations <span id="inverse-relations"></span>
两个 AR 类之间的关联声明往往像 *倒数* 那样。例如,`Customer` 是
两个 Active Record 类之间的关联声明往往是相互关联的。例如,`Customer`
通过 `orders` 关联到 `Order` ,而`Order` 通过 `customer` 又关联回到了 `Customer`
```php
@ -1274,7 +1274,7 @@ class Order extends ActiveRecord
}
```
现在开一下脑洞
现在考虑下面的一段代码
```php
// SELECT * FROM `customer` WHERE `id` = 123
@ -1324,15 +1324,15 @@ $customer2 = $order->customer;
echo $customer2 === $customer ? 'same' : 'not the same';
```
> Tip: 反向关联不能用在有 [连接表](#junction-table) 关联声明中。
> Note: 反向关联不能用在有 [连接表](#junction-table) 关联声明中。
也就是说,如果一个关联关系通过 [[yii\db\ActiveQuery::via()|via()]] 或 [[yii\db\ActiveQuery::viaTable()|viaTable()]] 声明,
你就不能再调用 [[yii\db\ActiveQuery::inverseOf()|inverseOf()]] 了。
## 保存关联数据 <span id="saving-relations"></span>
## 保存关联数据Saving Relations <span id="saving-relations"></span>
在使用关联数据时,您经常需要建立不同数据之间的关联或销毁
现有关联。这需要为定义的关联的列设置正确的值。通过使用 AR 活动记录
现有关联。这需要为定义的关联的列设置正确的值。通过使用 Active Record
你就可以编写如下代码:
```php
@ -1346,7 +1346,7 @@ $order->customer_id = $customer->id;
$order->save();
```
AR 提供了 [[yii\db\ActiveRecord::link()|link()]] 方法,可以更好地完成此任务:
Active Record 提供了 [[yii\db\ActiveRecord::link()|link()]] 方法,可以更好地完成此任务:
```php
$customer = Customer::findOne(123);
@ -1358,15 +1358,15 @@ $order->link('customer', $customer);
```
[[yii\db\ActiveRecord::link()|link()]] 方法需要指定关联名
和要建立关联的目标 AR 实例。该方法将修改属性的值
以连接两个 AR 实例,并将其保存到数据库。在上面的例子中,它将设置 `Order` 实例的 `customer_id` 属性
和要建立关联的目标 Active Record 实例。该方法将修改属性的值
以连接两个 Active Record 实例,并将其保存到数据库。在上面的例子中,它将设置 `Order` 实例的 `customer_id` 属性
`Customer` 实例的 `id` 属性的值,然后保存
到数据库。
> Tip: 你不能 link() 两个新的 AR 实例。(译者注:其中的一个必须是数据库中查询出来的)
> Note: 你不能关联两个新的 Active Record 实例。
当一个关联关系通过 [连接表](#junction-table) 定义时,此 [[yii\db\ActiveRecord::link()|link()]] 方法更能体现在党的领导下的中国特色社会主义的优越性
例如,你可以使用以下代码 link() `Order` 实例
使用 [[yii\db\ActiveRecord::link()|link()]] 的好处在通过 [junction table](#junction-table) 定义关系时更加明显
例如,你可以使用以下代码关联 `Order` 实例
`Item` 实例:
```php
@ -1375,12 +1375,12 @@ $order->link('items', $item);
上述代码会自动在 `order_item` 关联表中插入一行,以关联 order 和 item 这两个数据记录。
> Tip: [[yii\db\ActiveRecord::link()|link()]] 方法在保存相应的 AR 实例时,
> Info: [[yii\db\ActiveRecord::link()|link()]] 方法在保存相应的 Active Record 实例时,
将不会执行任何数据验证。在调用此方法之前,
您应当验证所有的输入数据。
[[yii\db\ActiveRecord::link()|link()]] 方法的反向操作是 [[yii\db\ActiveRecord::unlink()|unlink()]] 方法,
这将可以断掉两个 AR 实例间的已经存在了的关联关系。例如,
这将可以断掉两个 Active Record 实例间的已经存在了的关联关系。例如,
```php
$customer = Customer::find()->with('orders')->where(['id' => 123])->one();
@ -1396,9 +1396,9 @@ $customer->unlink('orders', $customer->orders[0]);
连接表中的外键或相应的行被删除。
## 跨数据库关联 <span id="cross-database-relations"></span>
## 跨数据库关联Cross-Database Relations <span id="cross-database-relations"></span>
AR 活动记录允许您在不同数据库驱动的 AR 类之间声明关联关系。
Active Record 允许您在不同数据库驱动的 Active Record 类之间声明关联关系。
这些数据库可以是不同的类型(例如 MySQL 和 PostgreSQL ,或是 MS SQL 和 MongoDB它们也可以运行在
不同的服务器上。你可以使用相同的语法来执行关联查询。例如,
@ -1438,13 +1438,13 @@ $customers = Customer::find()->with('comments')->all();
本节中描述的大多数关联查询功能,你都可以抄一抄。
> Tip: [[yii\db\ActiveQuery::joinWith()|joinWith()]] 这个功能限制于某些数据库是否支持跨数据库 JOIN 查询。
因此,你再上述的代码里就不能用此方法了,因为 MongoDB 不知道 JOIN 查询。
> Note: [[yii\db\ActiveQuery::joinWith()|joinWith()]] 这个功能限制于某些数据库是否支持跨数据库 JOIN 查询。
 因此,你再上述的代码里就不能用此方法了,因为 MongoDB 不支持 JOIN 查询。
## 自定义查询类 <span id="customizing-query-classes"></span>
## 自定义查询类Customizing Query Classes <span id="customizing-query-classes"></span>
默认情况下,[[yii\db\ActiveQuery]] 支持所有 AR 查询。要在 AR 类中使用自定义的查询类,
默认情况下,[[yii\db\ActiveQuery]] 支持所有 Active Record 查询。要在 Active Record 类中使用自定义的查询类,
您应该重写 [[yii\db\ActiveRecord::find()]] 方法并返回一个你自定义查询类的实例。
例如,
@ -1492,7 +1492,7 @@ class CommentQuery extends ActiveQuery
}
```
> Tip: 作为 [[yii\db\ActiveQuery::onCondition()|onCondition()]] 方法的替代方案,你应当
> Note: 作为 [[yii\db\ActiveQuery::onCondition()|onCondition()]] 方法的替代方案,你应当
调用 [[yii\db\ActiveQuery::andOnCondition()|andOnCondition()]] 或 [[yii\db\ActiveQuery::orOnCondition()|orOnCondition()]] 方法来附加新增的条件,不然在一个新定义的查询方法,已存在的条件可能会被覆盖。
然后你就可以先下面这样构建你的查询了:
@ -1503,7 +1503,7 @@ $inactiveComments = Comment::find()->active(false)->all();
```
> Tip: 在大型项目中,建议您使用自定义查询类来容纳大多数与查询相关的代码,
以使 AR 类保持简洁。
以使 Active Record 类保持简洁。
您还可以在 `Comment` 关联关系的定义中或在执行关联查询时,使用刚刚新建查询构建方法:
@ -1538,12 +1538,12 @@ $customers = Customer::find()->joinWith([
你依然可以使用自定义查询类、查询方法来达到一样的效果。
## 选择额外的字段
## 选择额外的字段Selecting extra fields
当 AR 实例从查询结果中填充时,从数据结果集中,
当 Active Record 实例从查询结果中填充时,从数据结果集中,
其属性的值将被相应的列填充。
你可以从查询中获取其他列或值,并将其存储在 AR 活动记录中。
你可以从查询中获取其他列或值,并将其存储在 Active Record 活动记录中。
例如,假设我们有一个名为 `room` 的表,其中包含有关酒店可用房间的信息。
每个房间使用字段 `length``width``height` 存储有关其空间大小的信息。
想象一下,我们需要检索出所有可用房间的列表,并按照体积大小倒序排列。
@ -1652,8 +1652,8 @@ class Room extends \yii\db\ActiveRecord
}
```
当 select 查询不提供 volume 体积时,这模型将能够自动计算体积的值出来
当访问模型的属性的时候。
当 select 查询不提供 volume 体积时,这模型将能够自动计算体积的值出来
当访问模型的属性的时候。
当定义关联关系的时候,你也可以计算聚合字段:
@ -1689,8 +1689,8 @@ class Customer extends \yii\db\ActiveRecord
}
```
使用此代码,如果 'select' 语句中存在 'ordersCount' - 它会从查询结果集获取数据填充 `Customer::ordersCount` 属性,
否则它会在被访问的时候,使用 `Customer::orders` 关联按需计算。
使用此代码,如果 'select' 语句中存在 'ordersCount' - 它会从查询结果集获取数据填充 `Customer::ordersCount` 属性,
否则它会在被访问的时候,使用 `Customer::orders` 关联按需计算。
这种方法也适用于创建一些关联数据的快捷访问方式,特别是对于聚合。
例如: