1

我正在尝试使用这样的外键创建表(使用迁移)

public function safeUp()
{
    $this->createTable('tbl_category', array(
        'id'=>'pk',
        'title'=>'string NOT NULL',
        'url'=>'string NOT NULL UNIQUE'
    ));
    $this->addForeignKey('FK_category', 'tbl_product', 'category_id', 'tbl_category', 'id', 'CASCADE', 'NO ACTION');    
}

它在 MySQL 中完美运行,但现在我想使用 SQLite,这段代码给出了一个错误,在 SQLite 中我无法向现有表添加外键,所以我查看了createTable方法的定义:

public integer createTable(string $table, array $columns, string $options=NULL)

并尝试使用$optionsparam 在此处添加我的外键,但它会生成以下内容:

CREATE TABLE 'tbl_category' (
    "id" integer PRIMARY KEY AUTOINCREMENT NOT NULL,
    "title" varchar(255) NOT NULL,
    "url" varchar(255) NOT NULL UNIQUE
)
CONSTRAINT FK_category
FOREIGN KEY tbl_product(category_id)
REFERENCES tbl_category(id)
ON DELETE CASCADE ON UPDATE NO ACTION

显然,“CONSTRAINT ...”代码应该在这些括号内,但事实并非如此。那么如何创建这个外键呢?

4

2 回答 2

7

解释

函数createTable在源代码中定义为:

public function createTable($table, $columns, $options=null)
{
    $cols=array();
    foreach($columns as $name=>$type)
    {
        if(is_string($name))
            $cols[]="\t".$this->quoteColumnName($name).' '.$this->getColumnType($type);
        else
            $cols[]="\t".$type;
    }
    $sql="CREATE TABLE ".$this->quoteTableName($table)." (\n".implode(",\n",$cols)."\n)";
    return $options===null ? $sql : $sql.' '.$options;
}

这告诉我所有选项都适用于通常在 Create 语句之后(但在最后一个分号之前)的内容,例如MySQL 中的ENGINECHARSET。SQLite 语法只是不同,并且不允许这样的选项。

addForeignKey函数不起作用,它只是没有编码:

public function addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete=null, $update=null)
{
    throw new CDbException(Yii::t('yii', 'Adding a foreign key constraint to an existing table is not supported by SQLite.'));
}

SQLite 不支持更改表以添加外键子句。

解决方案

长话短说,您应该将外键子句放在列定义中(在您的产品表中,而不是您的类别表中):

$this->createTable('tbl_product', array(
    'id'=>'pk',
    'name'=>'string NOT NULL',
    'category_id'=>'integer NOT NULL REFERENCES tbl_category(id)'
));

附录

外键的想法是子表应该声明它,而不是父表。

于 2012-11-02T14:33:19.890 回答
1

用 $this->execute 做了,我在其中放置了纯 SQL 语句。

于 2012-11-02T11:42:22.053 回答