2012-08-06 50 views
4

,用于存储关于某些网站用户定义的书签,我与复合键的表:关系的Yii ActiveRecord的用于表复合具有NULL键值

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为空时,为整本书设置书签,否则 - 对于某个页面。

相应的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( $书签)== 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以外。

+0

很久以前,我一直在使用YII,据我记得你应该使用书签:: model() - >('book');' – Leri 2012-08-06 12:04:45

+0

@PLB,我认为* Conditions *将被合并,所以不会有太大的区别(但是在这里+ 35°C,所以我可能是非常错误的)。 uisky,* book_id *这行没有NULL值,对吧? – 2012-08-06 12:27:56

+0

@Boris Belenski,正确,user_id和book_id没有NULL的 – uisky 2012-08-06 12:40:46

回答

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

由于事实上,具有独特的密钥,而不是主要和primaryKey()你使用hack来避免在复合PK中使用NULL列的不可能性。 ActiveRecord是一种ORM,所以SQL中的任何逻辑都必须翻译成AR(Yii会自动加载DB模式),并且它必须是正确的逻辑。

如果我是你,我会正常化的SQL是这样的: Normalized DB structure

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