[Yii2笔记]009 AR存储数据(Saving Data) [ 技术分享 ]
说明
学习Yii Framework 2(易2框架)的过程是漫长的,也是充满乐趣的,以下是我学习Yii2框架时对官网英文资料(请参见原文网址)的翻译和代码实现,提供了较完整的代码,供你参考。不妥之处,请多多指正!
原文网址:
http://www.yiiframework.com/doc-2.0/guide-db-active-record.html#inserting-updating-data
5、Saving Data(存储数据)
本文主题:AR存储数据(Saving Data)
5、Saving Data(存储数据)
使用Active Record,你可以很轻松将数据存储到数据库中,步骤如下: 1)准备一个Active Record实例 2)为Active Record属性赋新值 3)调用yii\ActiveRecord::save()存储数据到数据库中
例如:
// insert a new row of data
$customer = new Customer();
$customer->name = 'James';
$customer->email = 'james@example.com';
$customer->save();
// update an existing row of data
$customer = Customer::findOne(123);
$customer->email = 'james@newexample.com';
$customer->save();
save()方法可以插入一条新记录,也可编辑一条记录,其依据是Active Record实例的状态。如果实例是使用new操作符新创建的一个对象,调用save()将插入一条新记录;如果实例是使用查询方法获取的结果,调用save()方法将更新实例所关联的记录。
你可以通过检查isNewRecord属性值来区分Active Record实例的这种状态,在save()方法内也是使用此属性进行区分的:
public function save($runValidation = true, $attributeNames = null)
{
if ($this->getIsNewRecord()) {
return $this->insert($runValidation, $attributeNames);
} else {
return $this->update($runValidation, $attributeNames) !== false;
}
}
小贴士:你可以调用insert()或update()直接执行插入或更新操作。
//Data Validation(数据验证) 因为yii\db\ActiveRecord扩展自yii\base\Model,所以它也具有相同的数据验证特性。你可以重写rules()方法来定义验证规则,调用validate()方法来执行验证。 当你调用save()时,它也会自动调用validate(),只有当验证通过时,它才会真正存储数据;否则它只是返回false,你可以检查errors属性来获取验证错误信息。
小贴士:如果你确定数据无需验证(例如:数据来自可信源),你可以调用save(false)来跳过验证。
//块赋值(Massive Assignment) 象普通模型一样,Active Record实例也可以享用块赋值的便利,这样你就可以使用一行PHP代码将多个值赋到Active Record实例的属性中去了,代码见下例。 记住:只有safe属性才可以被块赋值。
$values = [
'name' => 'James',
'email' => 'james@example.com',
];
$customer = new Customer();
$customer->attributes = $values;
$customer->save();
// MongoDB,块赋值仅对safe属性生效
$values = [
'code'=>'aa',
'name'=>'apean',
'continent' => 'Asia',
'population'=>223,
];
$country = new Country();
$country->attributes = $values;
//将模型或AR中的所有属性设置为safe
public function rules() {
return [
[$this->attributes(),'safe'],
];
}
//更新记数器(Updating Counters)//counter//自增//加一
在数据表中增加或减少某字段的数值是个常规操作,我们称这些列为"计数列",你可以使用updateCounters()更新一列或多列计数列,例如:
$post = Post::findOne(100);
// UPDATE `post` SET `view_count` = `view_count` + 1 WHERE `id` = 100
$post->updateCounters(['view_count' => 1]);
// MongoDB:click=click+1,level=level+2
$article=ArticleInfo::findOne($id);
$article->updateCounters(['click'=>1,'level'=>2]);
注意:你可以使用yii\db\ActiveRecord::save()更新一个计数列,你可能会在一个错误的结果基础上进行增长,因为当多个请求读取和写入相同的计数值时,可能会有相同的计数值被存储进去。
//变动属性(Dirty Attributes) 当你调用save()对Active Record实例进行存储时,仅变动属性(dirty attributes)将被存储。当一个属性最近一次从数据库中加载或存储后,它的值发生了改变,则此属性就被认为是变动属性。注意:无论Active Record实例是否有变动属性,数据验证都将被执行。 Active Record自动维护变动属性列表,实现机制是它保存了属性值的一个旧版本,并将它们与最新的数据进行比较。你可以调用yii\ActiveRecord::getDirtyAttributes()来获取当前变动的属性。你也可以调用yii\ActiveRecord::markAttributeDirty()方法将一个属性明确的标示为变动属性。 你如果对变动前的属性值感兴趣,你可以调用getOldAttributes()或getOldAttribute()。
注意:旧数据和新数据之间是使用'==='操作符来进行,所以如果它们仅是类型不相同,则此属性也将被认为是变动属性。经常出现的一种情况是模型从HTML表单中接收的用户输入数据都将被认为是一个字符串,要确保为正确的数据类型,例如整型,你可以使用一个验证器:['attributeName', 'filter', 'filter' => 'intval']。此类工作可以使用PHP的类型转换函数,如:intval()、floatval()、boolval()等。
//默认属性值(Default Attribute Values) 有时你的表列或许在数据库中定义了默认值,你可能想将Active Record实例中的这些默认值装配到Web表单中去。为了避免要再书写一遍相同的默认值,你可以使用loadDefaultValues()以装配数据库预定义的(DB-defined)默认值到对应的Active Record属性中去:
//default
$customer=new Customer();
$customer->loadDefaultValues();
//当定义了'xyz'列时,$customer->xyz将被赋予默认值。
//属性类型转换(Attribute Typecasting) 使用yii\db\ActiveRecord的查询结果填充的属性值将根据数据表的schema信息自动进行数据类型转换。这样从表列中获取的整型数据就可以使用PHP的整型数据填充到ActiveRecord,布尔值对应布尔值,等等。尽管如此,数据类型转换机制有以下几点限制: 1、浮点值不能被转换,它将被转为字符串,否则将丢失精度。 2、转换整型值依赖于你所使用的操作系统的整型精度,尤其注意:是64位操作系统时,字段定义为'unsigned integer'或'big integer'将被转换为PHP整型;是32位操作系统时,将被转换成一个字符串。
注意:只有当查询结果集来填充ActiveRecord实例时,才执行属性的类型转换。当从HTTP请求加载数据或直接存取属性时将不会自动执行类型转换。当构建SQL语句进行ActiveRecord数据存储时,表schema也将被使用,以确保绑定到查询语句中的值是正确的类型。不管怎样,ActiveRecord实例属性值在存储过程中将不会被转换。
小贴士:你可以使用yii\behaviors\AttributeTypecastBehavior在ActiveRecord验证或存储时进行方便的属性值转换。
//更新多行数据(Updating Multiple Rows) 以上描述的方法都是工作于一个Active Record实例,对单一的表行数据进行插入或更新。要同时更新多行数据,你可以使用updateAll(),它是一个静态方法。
// UPDATE `customer` SET `status` = 1 WHERE `email` LIKE `%@example.com%`
Customer::updateAll(['status' => Customer::STATUS_ACTIVE], ['like', 'email', '@example.com']);
// MongoDB:将population==223(population是整型)的所有记录的continent字段更新为'Asia'
Country::updateAll(['continent' => 'Asia'],['population'=>223]);
//Country::updateAll(['continent' => 'Asia'],['population'=>'223']);//此句无效:整型223写成了字符串'223'
// MongoDB:将所有记录的continent字段更新为'Asia',没有限制条件,慎用!!
Country::updateAll(['continent' => 'Asia']);
相似的,你可以调用updateAllCounters()同时更新多条记录的计数列。
//将所有记录的population加1,没有限制条件,慎用!!
Country::updateAllCounters(['population' => 1]);
//将name=='china'的记录的population加1
Country::updateAllCounters(['population' => 1],['name'=>'china']);
(全文完)
共 0 条回复
阿江
最后登录:2024-03-03
在线时长:186小时21分
- 粉丝94
- 金钱16816
- 威望160
- 积分20276