具有NULL值的复合键的表的关系Yii ActiveRecord

时间:2012-08-06 12:00:08

标签: php activerecord yii

为了在某个站点上存储用户定义的书签,我有一个包含复合键的表:

CREATE TABLE bookmarks (
    user_id int not null,
    book_id int not null,
    page_id int,
    ...
);
CREATE UNIQUE INDEX ON bookmarks(user_id, book_id, page_id);

注意,page_id可以为NULL,而user_id和book_id则不能。当page_id为null时,为整本书设置书签,否则 - 为某个页面设置。

对应的ActiveRecord类定义了一些关系:

public function relations() {
    return array(
        "user"  => array(self::BELONGS_TO, "User",     "user_id"),
        "book"  => array(self::BELONGS_TO, "Book",     "book_id"),
        "page"  => array(self::BELONGS_TO, "Page",     "page_id"),
    );
}

和primaryKey()方法::

public function primaryKey() {
    return array("user_id", "book_id", "orig_id");
}

现在我想为一些用户获取整本书的所有书签。所以,我这样做:

$bookmarks = Bookmark::model()->findAll(array(
    "condition" => "t.user_id = :user_id AND t.page_id IS NULL",
    "params" => array(":user_id" => 1),
));

效果很好,返回4条记录,但很明显,我想使用书籍表中的一些相关数据:

$bookmarks = Bookmark::model()->findAll(array(
    "with" => "book",
    "condition" => "t.user_id = :user_id AND t.page_id IS NULL",
    "params" => array(":user_id" => 1),
));

现在我得到0条记录(count($ bookmarks)== 0),虽然生成的SQL语句选择了所有需要的数据,但CActiveRecord类却无法识别它。另一个奇怪的事情是,当我尝试获取所有页面书签时,一切都很好:

$bookmarks = Bookmark::model()->findAll(array(
    "with" => "book",
    "condition" => "t.user_id = :user_id AND t.page_id IS NOT NULL",
    "params" => array(":user_id" => 1),
));

我做错了什么?如何在第二个例子中使表达式返回一些数据? PHP 5.4.0,Yii 1.1.8,PostgreSQL 9.1.4,外部+ 32°C。

1 个答案:

答案 0 :(得分:3)

您的问题可以通过这种方式解决:

  1. 将代理PK 添加到书签表格(例如自动增量序列)。

  2. 删除primaryKey() 功能。

  3. 您也可以使用更方便的代码:

    public function relations()
    {
        return array(
            //...
            'wholeBook' => array(self::BELONGS_TO, 'Book', 'book_id', 'on'=>"page_id IS NULL", 'joinType'=>'INNER JOIN'),
            //...
        );
    }
    

    然后在控制器中:

    $bookmarks = Bookmark::model()->with('wholeBook')->findAllByAttributes(array('user_id'=>1));
    

    事实上,使用UNIQUE键而不是PRIMARY而primaryKey()使用hack来避免在复合PK中使用NULL列的不可能性。 ActiveRecord是一种ORM,因此SQL中的任何逻辑都必须转换为AR(Yii自动加载DB模式),并且它必须是正确的逻辑。

    如果我是你,我会将SQL标准化为以下内容: Normalized DB structure

    因为这是两种不同类型的书签,具有不同的关系。您应该只在视图逻辑中加入它们,而不是在关系结构中。 IMHO