### 新增數據
用 AR 而不是原生的 SQL 語句去執行數據庫查詢,可以調用直觀方法來實現相同目標。如,調用 yii\db\ActiveRecord::save() 方法將執行插入或更新輪詢,將在該 AR 類關聯的數據表新建或更新一行數據:
$customer = new Customer();
$customer->name = 'Qiang';
$customer->save(); // 一行新數據插入 customer 表
上面的代碼和使用下面的原生 SQL 語句是等效的,但顯然前者更直觀, 更不易出錯,并且面對不同的數據庫系統(DBMS, Database Management System)時更不容易產生兼容性問題。
$db->createCommand('INSERT INTO customer (name) VALUES (:name)', [
':name' => 'Qiang',
])->execute()
### 查詢數據
聲明 AR 類
要想聲明一個 AR 類,你需要擴展 yii\db\ActiveRecord 基類, 并實現 tableName 方法,返回與之相關聯的的數據表的名稱:
namespace app\models;
use yii\db\ActiveRecord;
class Customer extends ActiveRecord
{
/**
* @return string 返回該AR類關聯的數據表名
*/
public static function tableName()
{
return 'customer';
}
}
#### 訪問列數據
AR 把相應數據行的每一個字段映射為 AR 對象的一個個特性變量(Attribute) 一個特性就好像一個普通對象的公共屬性一樣(public property)。 特性變量的名稱和對應字段的名稱是一樣的,且大小姓名。
使用以下語法讀取列的值:
// "id" 和 "mail" 是 $customer 對象所關聯的數據表的對應字段名
$id = $customer->id;
$email = $customer->email;
要改變列值,只要給關聯屬性賦新值并保存對象即可:
$customer->email = 'james@example.com';
$customer->save();
建立數據庫連接
AR 用一個 yii\db\Connection 對象與數據庫交換數據。 默認的,它使用 db 組件作為其連接對象。詳見數據庫基礎章節, 你可以在應用程序配置文件中設置下 db 組件,就像這樣,
return [
'components' => [
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=testdb',
'username' => 'demo',
'password' => 'demo',
],
],
];
如果在你的應用中應用了不止一個數據庫,且你需要給你的 AR 類使用不同的數據庫鏈接(DB connection) ,你可以覆蓋掉 yii\db\ActiveRecord::getDb() 方法:
class Customer extends ActiveRecord
{
// ...
public static function getDb()
{
return \Yii::$app->db2; // 使用名為 "db2" 的應用組件
}
}
#### 查詢數據
AR 提供了兩種方法來構建 DB 查詢并向 AR 實例里填充數據:
yii\db\ActiveRecord::find()
yii\db\ActiveRecord::findBySql()
以上兩個方法都會返回 yii\db\ActiveQuery 實例,該類繼承自yii\db\Query, 因此,他們都支持同一套靈活且強大的 DB 查詢方法,如where(),join(),orderBy(),等等。 下面的這些案例展示了一些可能的玩法:
// 取回所有活躍客戶(狀態為 *active* 的客戶)并以他們的 ID 排序:
$customers = Customer::find()
->where(['status' => Customer::STATUS_ACTIVE])
->orderBy('id')
->all();
// 返回ID為1的客戶:
$customer = Customer::find()
->where(['id' => 1])
->one();
// 取回活躍客戶的數量:
$count = Customer::find()
->where(['status' => Customer::STATUS_ACTIVE])
->count();
// 以客戶ID索引結果集:
$customers = Customer::find()->indexBy('id')->all();
// $customers 數組以 ID 為索引
// 用原生 SQL 語句檢索客戶:
$sql = 'SELECT * FROM customer';
$customers = Customer::findBySql($sql)->all();
小技巧:在上面的代碼中,Customer::STATUS_ACTIVE 是一個在 Customer 類里定義的常量。(譯注:這種常量的值一般都是tinyint)相較于直接在代碼中寫死字符串或數字,使用一個更有意義的常量名稱是一種更好的編程習慣。
*有兩個快捷方法:findOne 和 findAll() 用來返回一個或者一組ActiveRecord實例。前者返回第一個匹配到的實例,后者返回所有。 例如:
*
// 返回 id 為 1 的客戶
$customer = Customer::findOne(1);
// 返回 id 為 1 且狀態為 *active* 的客戶
$customer = Customer::findOne([
'id' => 1,
'status' => Customer::STATUS_ACTIVE,
]);
// 返回id為1、2、3的一組客戶
$customers = Customer::findAll([1, 2, 3]);
// 返回所有狀態為 "deleted" 的客戶
$customer = Customer::findAll([
'status' => Customer::STATUS_DELETED,
]);
*以數組形式獲取數據
*
有時候,我們需要處理很大量的數據,這時可能需要用一個數組來存儲取到的數據, 從而節省內存。你可以用 asArray() 函數做到這一點:
// 以數組而不是對象形式取回客戶信息:
$customers = Customer::find()
->asArray()
->all();
// $customers 的每個元素都是鍵值對數組
批量獲取數據
在 Query Builder(查詢構造器) 里,我們已經解釋了當需要從數據庫中查詢大量數據時,你可以用 *batch query(批量查詢)*來限制內存的占用。 你可能也想在 AR 里使用相同的技巧,比如這樣……
// 一次提取 10 個客戶信息
foreach (Customer::find()->batch(10) as $customers) {
// $customers 是 10 個或更少的客戶對象的數組
}
// 一次提取 10 個客戶并一個一個地遍歷處理
foreach (Customer::find()->each(10) as $customer) {
// $customer 是一個 ”Customer“ 對象
}
// 貪婪加載模式的批處理查詢
foreach (Customer::find()->with('orders')->each() as $customer) {
}
操作數據
AR 提供以下方法插入、更新和刪除與 AR 對象關聯的那張表中的某一行:
yii\db\ActiveRecord::save()
yii\db\ActiveRecord::insert()
yii\db\ActiveRecord::update()
yii\db\ActiveRecord::delete()
AR 同時提供了一下靜態方法,可以應用在與某 AR 類所關聯的整張表上。 用這些方法的時候千萬要小心,因為他們作用于整張表! 比如,deleteAll() 會刪除掉表里所有的記錄。
yii\db\ActiveRecord::updateCounters()
yii\db\ActiveRecord::updateAll()
yii\db\ActiveRecord::updateAllCounters()
yii\db\ActiveRecord::deleteAll()
下面的這些例子里,詳細展現了如何使用這些方法:
// 插入新客戶的記錄
$customer = new Customer();
$customer->name = 'James';
$customer->email = 'james@example.com';
$customer->save(); // 等同于 $customer->insert();
// 更新現有客戶記錄
$customer = Customer::findOne($id);
$customer->email = 'james@example.com';
$customer->save(); // 等同于 $customer->update();
// 刪除已有客戶記錄
$customer = Customer::findOne($id);
$customer->delete();
// 刪除多個年齡大于20,性別為男(Male)的客戶記錄
Customer::deleteAll('age > :age AND gender = :gender', [':age' => 20, ':gender' => 'M']);
// 所有客戶的age(年齡)字段加1:
Customer::updateAllCounters(['age' => 1]);
須知:save() 方法會調用 insert() 和 update() 中的一個, 用哪個取決于當前 AR 對象是不是新對象(在函數內部,他會檢查 yii\db\ActiveRecord::isNewRecord 的值)。 若 AR 對象是由 new 操作符 初始化出來的,save() 方法會在表里插入一條數據; 如果一個 AR 是由 find() 方法獲取來的, 則 save() 會更新表里的對應行記錄。
數據輸入與有效性驗證
由于AR繼承自yii\base\Model,所以它同樣也支持Model的數據輸入、驗證等特性。例如,你可以聲明一個rules方法用來覆蓋掉yii\base\Model::rules()里的;你也可以給AR實例批量賦值;你也可以通過調用yii\base\Model::validate()執行數據驗證。
當你調用 save()、insert()、update() 這三個方法時,會自動調用yii\base\Model::validate()方法。如果驗證失敗,數據將不會保存進數據庫。
下面的例子演示了如何使用AR 獲取/驗證用戶輸入的數據并將他們保存進數據庫:
// 新建一條記錄
$model = new Customer;
if ($model->load(Yii::$app->request->post()) && $model->save()) {
// 獲取用戶輸入的數據,驗證并保存
}
// 更新主鍵為$id的AR
$model = Customer::findOne($id);
if ($model === null) {
throw new NotFoundHttpException;
}
if ($model->load(Yii::$app->request->post()) && $model->save()) {
// 獲取用戶輸入的數據,驗證并保存
}
讀取默認值
你的表列也許定義了默認值。有時候,你可能需要在使用web表單的時候給AR預設一些值。如果你需要這樣做,可以在顯示表單內容前通過調用loadDefaultValues()方法來實現:
php $customer = new Customer(); $customer->loadDefaultValues(); // ... 渲染 $customer 的 HTML 表單 ...
AR的生命周期
理解AR的生命周期對于你操作數據庫非常重要。生命周期通常都會有些典型的事件存在。對于開發AR的behaviors來說非常有用。
當你實例化一個新的AR對象時,我們將獲得如下的生命周期:
constructor
yii\db\ActiveRecord::init(): 會觸發一個 yii\db\ActiveRecord::EVENT_INIT 事件
當你通過 yii\db\ActiveRecord::find() 方法查詢數據時,每個AR實例都將有以下生命周期:
constructor
yii\db\ActiveRecord::init(): 會觸發一個 yii\db\ActiveRecord::EVENT_INIT 事件
yii\db\ActiveRecord::afterFind(): 會觸發一個 yii\db\ActiveRecord::EVENT_AFTER_FIND 事件
當通過 yii\db\ActiveRecord::save() 方法寫入或者更新數據時, 我們將獲得如下生命周期:
yii\db\ActiveRecord::beforeValidate(): 會觸發一個 yii\db\ActiveRecord::EVENT_BEFORE_VALIDATE 事件
yii\db\ActiveRecord::afterValidate(): 會觸發一個 yii\db\ActiveRecord::EVENT_AFTER_VALIDATE 事件
yii\db\ActiveRecord::beforeSave(): 會觸發一個 yii\db\ActiveRecord::EVENT_BEFORE_INSERT 或 yii\db\ActiveRecord::EVENT_BEFORE_UPDATE 事件
執行實際的數據寫入或更新
yii\db\ActiveRecord::afterSave(): 會觸發一個 yii\db\ActiveRecord::EVENT_AFTER_INSERT 或 yii\db\ActiveRecord::EVENT_AFTER_UPDATE 事件
最后,當調用 yii\db\ActiveRecord::delete() 刪除數據時, 我們將獲得如下生命周期:
yii\db\ActiveRecord::beforeDelete(): 會觸發一個 yii\db\ActiveRecord::EVENT_BEFORE_DELETE 事件
執行實際的數據刪除
yii\db\ActiveRecord::afterDelete(): 會觸發一個 yii\db\ActiveRecord::EVENT_AFTER_DELETE 事件