4

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

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 条记录,但显然,我想使用 book 表中的一些相关数据:

$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 外部。

4

1 回答 1

3

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

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

  2. 删除primaryKey()功能。

您还可以使用更方便的代码:

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 标准化为如下内容: 标准化数据库结构

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

于 2012-08-07T15:10:03.800 回答