与其他表条件的关系记录


Yii Relational record with condition from other table

我有一个类似于以下的关系记录:

  • 存在id为
  • 的用户(表用户)
  • 有id,名称
  • 的类别(表类别)
  • 有带有id, body, category_id
  • 的文章(表文章)>>>>>>>>>>>>>>>>

用户可以看到一个类别中所有文章的列表。他们可以点击一篇文章,它将添加一个条目(user_id, article_id)到read_articles表。

我希望能够使用Yii的ActiveRecord从当前用户尚未阅读的给定类别中获取所有文章并显示这些文章。我一直在考虑它在SQL方面一点,但我不确定如何适合它到我的ActiveRecord设置。我的第一个想法是在Article活动记录上设置参数化作用域:

public function unread( $userId )
{
    $this->getDbCriteria()->mergeWith( array(
        'alias' => 'articles',
        'condition' => 'not exists (SELECT * '
            . 'FROM user_read_articles '
            . 'WHERE articles.id=user_read_articles.article_id '
            . 'AND read_articles.user_id=' . (int)$userId
            . ')',
    ) );
}

看起来还行,但是我感觉很脏。

是否有一个更干净的方法来做我所说的在ActiveRecord?或者我应该考虑转向更简单的SQL,自己处理这样的事情(但失去了AR的很多好特性)?

编辑以下是上述模型的关系:(免责声明,这些只是截断了相关的部分)

UserActiveRecord

public function relations()
{
    return array(
        'categories' => array(
            self::HAS_MANY,
            'UserCategoryActiveRecord',
            'user_id' ),
        // I added this early using gii, never really used it...
        'readArticles' => array(
            self::HAS_MANY,
            'UserReadArticleActiveRecord',
            'user_id' ),
    );
}

UserCategoryActiveRecord

public function relations()
{
    return array(
        'user' => array(
            self::BELONGS_TO,
            'UserActiveRecord',
            'user_id' ),
        'articles' => array(
            self::HAS_MANY,
            'ArticleActiveRecord',
            'category_id',
            'order' => 'articles.pub_date DESC' ),
    );
}

ArticleActiveRecord

public function relations()
{
    return array(
        'category' => array(
            self::BELONGS_TO,
            'CategoryActiveRecord',
            'category_id' ),
    );
}

我也做了一个"UserReadArticleActiveRecord"早,因为我正在建设这个,但我从来没有使用过这个模型,它几乎只是空的。

老实说,我一直在考虑转移到Symfony2和Doctrine,完全抛弃活动记录。我知道这不能解决这个问题,但我可能会放弃这个,暂时保留我当前的解决方案。

要获取read文章,您可以在User模型上定义一个many - many关系,如下所示:

http://www.yiiframework.com/doc/guide/1.1/en/database.arr

我不认为你需要代理模型UserReadArticles,你只需要正确地定义关系。

要获得未读文章,我也有麻烦考虑Yii的方式来做到这一点,但比使用子选择查询更有效的方法是对user_read_articles做一个LEFT JOIN,并检查user_read_articles中的一列是否为空(没有匹配的行),就像这样:

$this->getDbCriteria()->mergeWith( array(
    'alias' => 'articles',
    'join' => 'LEFT JOIN user_read_articles ON articles.id=user_read_articles.article_id',
    'condition' => 'user_read_articles.article_id IS NULL',
) );