Yii模型:在Yii模型中使用动态表名

时间:2012-04-17 06:56:09

标签: php yii yii-cmodel

我有一个Yii模型将使用(稍后)多个数据库,表前缀将基于代码。

例如:

AMI_tablename,BMI_ AMI_tablename等

这些表格相同,但在不同的数据库中。

我想知道如何在运行时向Yii模型提供动态表名?

我尝试使用setter函数,但是父类CActiveRecord给出了一个错误,因为它没有从子模型类中获取值。

所以这是我的模型代码(只有我有问题的部分)

class RevShareModel extends CActiveRecord
{

    public $prefix;

    public static function model($className=__CLASS__)
    {
        return parent::model($className);
    }

    /**
     * @return string the associated database table name
     */
    public function tableName()
    {
        return $this->prefix . '_revshare_model';
    }

现在在我的控制器的某个地方

$obj = RevShareModel::model();
$obj->prefix ="BMI";
$obj->tableName();
$obj->findByPk(1);

exit;

但我得到的错误是:

CDbException

The table "_revshare_model" for active record class "RevShareModel" cannot be found in the database.

C:\wamp\www\framework\db\ar\CActiveRecord.php(2264)

似乎当CActiveRecord调用tableName()方法时,它不会获得$前缀。

5 个答案:

答案 0 :(得分:5)

您遇到此类错误,因为表名实际存储在模型的元数据中。您可以通过检查返回$model->getMetaData()对象的CActiveRecordMetaData的内容来查看。要更新元数据,您应在更改模型的'prefix'属性后调用$model->refreshMetaData(),例如:

...
$obj->prefix ="BMI";
$obj->refreshMetadata();
...

这绝对可以解决问题。

答案 1 :(得分:2)

您必须覆盖CActiveRecord::tableName方法(可能在模型的抽象基类中)。这是默认情况下的作用:

public function tableName()
{
    return get_class($this);
}

以下是您可以将其更改为:

abstract class MyActiveRecord extends CActiveRecord
{
    public $prefix; // should probably be private, your call

    public function tableName()
    {
        return $prefix.'_'.get_class($this);
    }
}

答案 2 :(得分:1)

这就是我解决这个问题的方法。

private static $_tableName;

public function __construct($tableName)
{
    if(strlen($tableName) == 0)
    {
        return false;
    }

    if(strlen($tableName)>0){
        self::$_tableName = $tableName;
    }

    self::setIsNewRecord(true);
}

public static function model($tableName)
{
    if(strlen($tableName) == 0)
    {
        return false;
    }

    $className=__CLASS__;

    if(strlen($tableName)>0){
        self::$_tableName = $tableName;
    }

    return parent::model($className);
}

public function tableName()
{
    return '{{'.self::$_tableName.'}}';
}

public function setTableName($tableName)
{
    self::$_tableName = $tableName;
}

...

当我使用这个模型时,我只是将表的名称放在括号中:

$model = new ClassName($tableName);

答案 3 :(得分:1)

我有同样的问题。 我有一个模型,但我希望将数据保存在不同的表中。所以我在保存数据之前更改了表名。

public $tbl_name = 'tbl_user_1';//default table
public function tableName()
{
return $this->tbl_name;
}
public function saveDataReg(){
    $mKey = $this->selfMHash($this->username);
    $modKey = $mKey % 2;
    $this->tbl_name = 'tbl_user_' . $modKey;

    $this->refreshMetadata();//change the default Metadata

    $this->save();
}
public function selfMHash($key){
    $md5 = substr(md5($key), 0, 8);
    $seed = 31;
    $hash = 0;

    for($i=0; $i<8; $i++){
        $hash = $hash * $seed + ord($md5{$i});
        $i++;
    }

    return $hash & 0x7FFFFFFF;
}

现在我发现在使用refreshMetadata功能时不会更改元数据。 最后我更改了原始代码

    public function refreshMetaData()
{
    $finder=self::model(get_class($this));
    $finder->_md=new CActiveRecordMetaData($finder);
    if($this!==$finder)
        $this->_md=$finder->_md;

    //return var_dump($this);
}

public function new_refreshMetaData()
{
    $finder=self::model(get_class($this));
    $finder->_md=new CActiveRecordMetaData($this);
    if($this!==$finder)
        $this->_md=$finder->_md;

    //return var_dump($this);
}

我重写了refreshMetaData的功能,并查找了CActiveRecordMetaData的参数。

$this->new_refreshMetadata();//use new function

然后它奏效了。 我不明白问题的原因。

答案 4 :(得分:0)

您可以使用MyModel::model()->tableName(),但请不要忘记写{{table}}