我有以下型号:User
列{id,用户名,密码,用户类型}Admin
包含列{id、用户id、全名等}Editor
包含列{id、用户id、全名等}
他们的关系是User
:'admin' => array(self::HAS_ONE, 'Admin', 'user_id'),'editor' => array(self::HAS_ONE, 'Editor', 'user_id'),
Admin
:'user' => array(self::BELONGS_TO, 'User', 'user_id'),
Editor
:'user' => array(self::BELONGS_TO, 'User', 'user_id'),
现在我在fullName
模型中设置了一个虚拟属性User
,如下所示
public function getFullName()
{
if($this->user_type=='admin')
return $this->admin->full_name;
else if($this->user_type=='editor')
return $this->editor->full_name;
}
我可以在GridView中显示虚拟属性
fullName
,但如何向该属性添加筛选器并使其在GridView中可排序?UPADE 1:
我根据@jon的答案更新了models search()函数,如下所示
public function search()
{
$criteria=new CDbCriteria;
$criteria->select=array('*','COALESCE( editor.full_name,admin.first_name, \'\') AS calculatedName');
$criteria->with=array('editor','admin');
$criteria->compare('calculatedName',$this->calculatedName,true);
$criteria->compare('email',$this->email,true);
$criteria->compare('user_type',$this->user_type);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
管理员和编辑器的名称都正确地显示在gridview中。但当我通过过滤器进行搜索时,会出现以下异常:
CDbCommand failed to execute the SQL statement: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'calculatedName' in 'where clause'. The SQL statement executed was: SELECT COUNT(DISTINCT `t`.`id`) FROM `user` `t` LEFT OUTER JOIN `editor` `editor` ON (`editor`.`user_id`=`t`.`id`) LEFT OUTER JOIN `admin` `admin` ON (`admin`.`user_id`=`t`.`id`) WHERE (calculatedName LIKE :ycp0) (C:\xampplite\htdocs\yii\framework\db\CDbCommand.php:528)</p><pre>#0 C:\xampplite\htdocs\yii\framework\db\CDbCommand.php(425):
我怎样才能摆脱这个?
更新2:
我的错误。我换线的时候很好
$criteria->compare('calculatedName',$this->calculatedName,true);
到
$criteria->compare('COALESCE( editor.full_name,admin.first_name, \'\')',$this->calculatedName,true);
顺便说一句thanx@jon。
最佳答案
您在这里要做的是有效地将计算列添加到结果集中。假设在用于获取结果的sql查询中,您将同时连接Admin
和Editor
表,因此Admin.full_name
和Editor.full_name
是计算所需值所涉及的两列。
因为至少有一个Admin.full_name
和Editor.full_name
总是NULL
,所以计算最终值的公式是
COALESCE(Admin.full_name, Editor.full_name, '')
现在已经有了计算公式,您需要执行以下步骤:
向模型中添加读写列以接收计算列
创建一个连接两个表并包含计算列的
CDbCriteria
。创建一个
CSort
描述计算列应如何影响记录顺序创建使用这些条件和排序选项的
CActiveDataProvider
。将数据提供程序馈送到您的
CGridView
因此,首先向模型添加一个公共属性:
public $calculatedName;
然后:
$criteria = new CDbCriteria(array(
'select' => array(
'*',
'COALESCE(Admin.full_name, Editor.full_name, \'\') AS calculatedName',
),
'with' => array('Admin', 'Editor'),
// other options here
));
$sort = new CSort;
$sort->attributes = array(
'calculatedName' => array(
'asc' => 'COALESCE(Admin.full_name, Editor.full_name, \'\')',
'desc' => 'COALESCE(Admin.full_name, Editor.full_name, \'\') DESC',
),
// other sort order definitions here
);
$dataProvider = new CActiveDataProvider('User', array(
'criteria' => $criteria,
'sort' => $sort,
));
最后,使用
$dataProvider
填充网格;使用calculatedName
作为列名。抱歉,如果我弄错了一些细节,因为我没有真正运行这个。
更新:如果将
CDbCriteria.select
指定为字符串,并且该字符串包含任何不用于分隔列的逗号(例如用于分隔COALESCE
参数的逗号),那么yii就不喜欢它。谢天谢地CDbCriteria
还允许将列作为数组传入,从而解决了这个问题。我更新了上面的代码以匹配。对于任何好奇的人来说,违规代码是this。