1

我有一个 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() 方法时它没有得到 $prefix。

4

5 回答 5

5

你有这样的错误,因为表名实际上存储在模型的元数据中。您可以通过检查$model->getMetaData()which 返回CActiveRecordMetaData对象的内容来看到这一点。要刷新元数据,您应该$model->refreshMetaData()在更改模型的“前缀”属性后调用,例如:

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

这肯定会成功。

于 2013-11-13T21:28:06.760 回答
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);
    }
}
于 2012-04-17T06:59:10.753 回答
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);
于 2012-08-17T19:38:30.503 回答
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

然后它起作用了。我不明白问题的原因。

于 2013-12-17T09:13:04.327 回答
0

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

于 2014-03-14T08:28:25.753 回答