activerecord java里的attributes属性不管怎么样都是null

ruby on rails - Callback for changed ActiveRecord attributes? - Stack Overflow
Insights on the world's developers
Demographics. Technologies. Salaries. Career satisfaction.
I am aware of ActiveRecord::Dirty and the related methods, but I don't see a means by which I can subscribe to an attribute changed event.
Something like:
class Person & ActiveRecord::Base
def attribute_changed(attribute_name, old_value, new_value)
attribute_changed do |attribute_name, old_value, new_value|
Is there a Rails standard or plugin for this?
I feel that it must be there somewhere and I'm just missing it.
3,06622451
cwninja's answer should do the trick, but there is a little bit more to it.
First of all, the base attribute handling is done with the write_attribute method so you should be tapping into this.
Rails also does have a built in callback structure which could be nice to tap into though it doesn't allow for passing arguments which is a bit of an annoyance.
Using custom callbacks you could do it like this:
class Person & ActiveRecord::Base
def write_attribute(attr_name, value)
attribute_changed(attr_name, read_attribute(attr_name), value)
def attribute_changed(attr, old_val, new_val)
"Attribute Changed: #{attr} from #{old_val} to #{new_val}"
If you wanted to try to use Rails callbacks (especially useful if you might have multiple callbacks and/or subclassing) you could do something like this:
class Person & ActiveRecord::Base
define_callbacks :attribute_changed
attribute_changed :notify_of_attribute_change
def write_attribute(attr_name, value)
returning(super) do
@last_changed_attr = attr_name
run_callbacks(:attribute_changed)
def notify_of_attribute_change
attr = @last_changed_attr
old_val, new_val = send("#{attr}_change")
"Attribute Changed: #{attr} from #{old_val} to #{new_val}"
8,652770116
For Rails 3:
class MyModel & ActiveRecord::Base
after_update :my_listener, :if =& :my_attribute_changed?
def my_listener
puts "Attribute 'my_attribute' has changed"
Commented in:
I don't find official documentation about this.
18.1k575112
For Rails 4
def attribute=(value)
super(value)
your_callback(self.attribute)
If you want to overwrite the value of attribute you should use write_attribute(:attribute, your_callback(self.attribute)) and not attribute= or you'll loop over it until you get a stack too deep exception.
def attribute_changed(attribute_name, old_value, new_value)
def attribute=(attribute_name, value)
returning(super) do
attribute_changed(attribute_name, attribute_was(attribute_name), attribute(attribute_name))
Just invented this now, but it should work.
6,86911522
You could always access the private method changed_attributes and check the keys there using a before_save and do with it what you will.
86.4k18197226
The easiest way that I found:
after_save :my_method, :if =& Proc.new{ self.my_attribute_changed? }
def my_method
... do stuff...
Your Answer
Sign up or
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Post as a guest
By posting your answer, you agree to the
Not the answer you're looking for?
Browse other questions tagged
rev .25515
Stack Overflow works best with JavaScript enabled深入理解 yii2的Active Record
yii2 中的 &$model-&attribute() & , &$model-&attributes &, & $model-&attributes= [...], model-&fields(),&$model-&toArray();
以下依次进行剖析:
$this-&attributes()
执行的是model的attributes()方法,返回的数据库的字段数组, yii\db\ActiveRecord&代码如下:
public function attributes()
return array_keys(static::getTableSchema()-&columns);
执行返回结果示例:
array (size=14)
0 =& string 'id' (length=2)
1 =& string 'username' (length=8)
2 =& string 'password_hash' (length=13)
3 =& string 'password_reset_token' (length=20)
4 =& string 'email' (length=5)
5 =& string 'auth_key' (length=8)
6 =& string 'status' (length=6)
7 =& string 'created_at' (length=10)
8 =& string 'updated_at' (length=10)
9 =& string 'password' (length=8)
10 =& string 'role' (length=4)
11 =& string 'access_token' (length=12)
12 =& string 'allowance' (length=9)
13 =& string 'allowance_updated_at' (length=20)
var_dump($this-&attributes) 执行的是函数:&\yii\base\model-&getAttributes(),该函数代码如下
public function getAttributes($names = null, $except = [])
$values = [];
if ($names === null) {
$names = $this-&attributes();
foreach ($names as $name) {
$values[$name] = $this-&$
foreach ($except as $name) {
unset($values[$name]);
也就是说,先通过 &$this-&attributes()方法,得到数据库表的字段数组
然后 依次遍历,查看各个属性,$this-&$name获取各个字段对应的值,而这个访问的是对象的属性,是通过魔术方法__get 从private属性 \yii\db\BaseActiveRecord::$_attributes 获取的,也就是说数组的结构是先用数据库字段作为数组的key, value是从数组&\yii\db\BaseActiveRecord::$_attributes中取值
然后拼起来的数组,也就是只有数据库里面的部分,对于model中定义的成员变量和其他的属性,这里是不做输出的。仅仅是数据库的字段部分。
如果您想得到一些定义的成员变量,但是又不想定义fields那么麻烦,您可以通过
$table_attr = $this-&attributes();
$public_x = [ 'password_repeat'];
$arr = array_merge($table_attr,$public_x );
$model-&getAttributes($arr);
返回您想访问的所有的属性和成员变量(注意:我说的属性,指的是不是成员变量的属性。)
魔术方法从&\yii\db\BaseActiveRecord::$_attributes 中取值,如果不存在,返回null
魔兽方法如下:&\yii\db\BaseActiveRecord::__get & & __sete
public function __get($name)
if (isset($this-&_attributes[$name]) || array_key_exists($name, $this-&_attributes)) {
return $this-&_attributes[$name];
} elseif ($this-&hasAttribute($name)) {
if (isset($this-&_related[$name]) || array_key_exists($name, $this-&_related)) {
return $this-&_related[$name];
$value = parent::__get($name);
if ($value instanceof ActiveQueryInterface) {
return $this-&_related[$name] = $value-&findFor($name, $this);
public function __set($name, $value)
if ($this-&hasAttribute($name)) {
$this-&_attributes[$name] = $
parent::__set($name, $value);
因此,在$_attributes不存在的值,就会被赋值null。
$this-&attributes = array();
这个执行的是
yii\base\model-&setAttributes($values, $safeOnly = true);
代码如下:
public function setAttributes($values, $safeOnly = true)
if (is_array($values)) {
$attributes = array_flip($safeOnly ? $this-&safeAttributes() : $this-&attributes());
foreach ($values as $name =& $value) {
if (isset($attributes[$name])) {
$this-&$name = $
} elseif ($safeOnly) {
$this-&onUnsafeAttribute($name, $value);
也就是块赋值,根据场景定义的字段,而且是只有这些字段赋值。
原理就是 将&
1.过滤出来场景允许的安全属性,然后进行赋值
2.如果存在成员变量,那么首先进行成员变量的赋值。
& 如果成员变量不存在,则会使用到__set魔兽方法,添加到 & yii\db\BaseActiveRecord 的private属性$_attributes 数组中
因此,如果在数据库中有一个字段password,如果你在AR类中也定义了一个password,那么就不会保存到&private属性$_attributes 数组中
当然,这个不会影响到保存,因为$model-&attributes 是通过 $this-&$name 的方式读取,而不是通过&private属性$_attributes 数组读取,
通过&&$this-&$name 的方式读取 ,定义的成员变量也是会保存到数据库中的
造成的后果就是 &private属性$_attributes 数组 没有password这个key,fields函数返回就没有password,进而toArray()返回的也没有password。
4.model-&fields()
这个方法默认的值,是抽象方法 yii\db\BaseActiveRecord 的private属性$_attributes
public function fields()
$fields = array_keys($this-&_attributes);
return array_combine($fields, $fields);
也就是说:通过private &$_attributes 数组的key
$model-&toArray()
这个函数的输出,是将 fields 返回的数组输出,从第4部分,可以看到,fields默认是由&&yii\db\BaseActiveRecord 的private属性$_attributes 的key得到
所以,toArray默认是将$_attributes的值得出,如果想在这里添加类的成员变量,可以fields函数中添加:
public function fields()
$fields = parent::fields();
$fields['password_repeat'] = 'password_repeat';
//$fields['rememberMe'] = function ($model) {
return $model-&rememberMe . ' ' . $model-&password_
$fields数组的key 是属性或成员变量,值也是key &通过$model-&password_repeat得到对应的值
如果想自定义,可以通过函数的方式获取。
当findOne得到一个AR实例后
$_attributes 里面保存的是所有的属性
$_oldAttributes里面保存的也是所有的数据库查询出来的属性,和$_attributes一样
当对这个对象重新赋值,实际上是吧值写入到了$_attributes ,而 $_oldAttributes的值是不变的
在最终的save的时候,查看两个数组的差异,进行update对应的字段,
在这里也就看出,实际上AR读取的字段值,不是AR类的成员变量,而是通过__get &__set方法得到的对应的值
而这个值,就是从$_attributes这个private属性中取到的值。
BaseActiveRecord函数:
public function __set($name, $value)
if ($this-&hasAttribute($name)) {
$this-&_attributes[$name] = $
parent::__set($name, $value);
public function __get($name)
if (isset($this-&_attributes[$name]) || array_key_exists($name, $this-&_attributes)) {
return $this-&_attributes[$name];
} elseif ($this-&hasAttribute($name)) {
if (isset($this-&_related[$name]) || array_key_exists($name, $this-&_related)) {
return $this-&_related[$name];
$value = parent::__get($name);
if ($value instanceof ActiveQueryInterface) {
return $this-&_related[$name] = $value-&findFor($name, $this);
所以,通过
$user = User::findOne(1)得到的model对象,
private $_attributes 存储的是数据库里面的值,以及对其赋值
$user-&fields() 得到的是 $_attributes 里面含有的字段,因此就是所有的数据表字段
&$user-&toArray()得到的是所有数据库的字段,也就是说,在默认情况下 toArray的输出的字段,是由 private &$_attributes字段决定的
当然,如果在model中进行了定义新字段,
public $password_
然后再fields中执行
public function fields() 这个函数中添加
$fields['password_repeat'] = 'password_repeat';
public function fields()
$fields = parent::fields();
$fields['password_repeat'] = 'password_repeat';
//$fields['rememberMe'] = function ($model) {
return $model-&rememberMe . ' ' . $model-&password_
通过asArray就输出了 & password_repeat字段了
对于new的新的AR对象
$model = new Useradmin();
$model-&attributes = $this-&getValues1();
public function getValues1(){
'username' =& 'terry',
'password' =& 'passfdafds',
//'password' =& 'passfdafds',
'password_repeat' =& 'passfdafds',
'email' =& 'email',
'created_at'
=& ' 11:11:11',
'access_token' =& null,
'rememberMe' =& 44,
$model-&attributes = $this-&getValues1(); &这个是块赋值,执行的是setAttributes方法,先通 场景 scrnarios函数 &验证是否是安全属性,
如果是,则把数据插入到 private $_attributes中
var_dump($model-&attributes());
var_dump($model-&toArray());
var_dump($model-&attributes);
array (size=14)
0 =& string 'id' (length=2)
1 =& string 'username' (length=8)
2 =& string 'password_hash' (length=13)
3 =& string 'password_reset_token' (length=20)
4 =& string 'email' (length=5)
5 =& string 'auth_key' (length=8)
6 =& string 'status' (length=6)
7 =& string 'created_at' (length=10)
8 =& string 'updated_at' (length=10)
9 =& string 'password' (length=8)
10 =& string 'role' (length=4)
11 =& string 'access_token' (length=12)
12 =& string 'allowance' (length=9)
13 =& string 'allowance_updated_at' (length=20)
array (size=6)
'username' =& string 'terry' (length=5)
'password' =& string 'passfdafds' (length=10)
'email' =& string 'email' (length=5)
'created_at' =& string ' 11:11:11' (length=19)
'access_token' =& null
'password_repeat' =& string 'passfdafds' (length=10)
array (size=14)
'id' =& null
'username' =& string 'terry' (length=5)
'password_hash' =& null
'password_reset_token' =& null
'email' =& string 'email' (length=5)
'auth_key' =& null
'status' =& null
'created_at' =& string ' 11:11:11' (length=19)
'updated_at' =& null
'password' =& string 'passfdafds' (length=10)
'role' =& null
'access_token' =& null
'allowance' =& null
'allowance_updated_at' =& null因为rememberMe不是安全属性,所以块赋值失败
$model-&attributes() 返回的是数据库中所有的字段数组
$model-&toArray()返回的是 $_attributes 属性数组
$model-&attributes 返回的是 key为&$model-&attributes() 返回的key &,值为&&$_attributes 属性数组的对应值,不存在则为null
对于model的foreach
foreach($model as $k=&$v){
echo $k.&=&&.$v.&&br/&&;
输出的是属性 $model-&attributes &也就是&$model-&getAttributes()函数返回的结果。
对应 model的其他的成员变量是不输出的。需要通过
$model-&xxxx调用
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:798866次
积分:19413
积分:19413
排名:第406名
原创:1070篇
转载:306篇
评论:71条
阅读:6121
(7)(5)(5)(5)(9)(3)(6)(9)(9)(6)(12)(8)(22)(30)(48)(67)(60)(20)(11)(9)(12)(30)(14)(34)(18)(23)(22)(13)(21)(22)(41)(27)(39)(16)(22)(15)(26)(37)(42)(56)(23)(2)(5)(10)(17)(2)(1)(1)(1)(6)(2)(2)(11)(23)(10)(22)(10)(48)(50)(29)(152)(70)ActiveRecord为什么插入的数据都是NULL? - 问答 - Yii Framework 中文社区
ActiveRecord为什么插入的数据都是NULL?
悬赏 10 金钱
User继承于yii\db\ActiveRecord,空的类。
$user = new \frontend\models\User();
$user-&username = 'x';
$user-&save();
插入到数据库后,username值是NULL
空的类肯定不行啊,你至少得指定哪个表,也就是重载
public static function tableName()
return 'user';
没有找到数据。
您需要登录后才可以回答。 |

我要回帖

更多关于 jfinal activerecord 的文章

 

随机推荐