【问题标题】:Yii Models: Using dynamic table name in a Yii modelYii 模型:在 Yii 模型中使用动态表名
【发布时间】:2012-04-17 06:56:08
【问题描述】:

我有一个 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)

好像当 tableName() 方法被 CActiveRecord 调用时它没有得到 $prefix。

【问题讨论】:

    标签: php yii yii-cmodel


    【解决方案1】:

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

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

    这绝对可以解决问题。

    【讨论】:

    • 我已经发现我必须使用 refreshMetaData 但我无法以某种方式更新这个问题。我接受了你的回答,因为我做了同样的事情。
    【解决方案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);
        }
    }
    

    【讨论】:

    • 我已经覆盖了它但是如何为这个模型提供前缀代码?
    • @Arfeen:添加属性或动态生成前缀,取决于你想要做什么。查看更新。
    • 但问题是当 CActiveRecord 它自己调用 tableName() 时,它不会得到 $prefix 中的值...对吗?这就是问题所在。
    • @Arfeen:我不确定我理解你的意思。您能否在问题中添加一些示例代码?
    • @Arfeen:你确定这正是你的代码的样子,没有错别字(例如$prefix.'...' 而不是$this->prefix.'...')?据我所知,它应该可以工作。它是否通过error_reporting(E_ALL) 发出任何通知?
    【解决方案3】:

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

    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);
    

    【讨论】:

    • 在提供解决问题的代码时,最好也至少简要解释一下它是如何工作的,这样阅读的人就不必在脑海中逐行解析来理解差异.
    • 为什么会有私有静态属性?
    【解决方案4】:

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

    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
    

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

    【讨论】:

      【解决方案5】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-21
        • 1970-01-01
        相关资源
        最近更新 更多