选择hasMany关系的最新记录

时间:2011-10-02 09:12:43

标签: cakephp

我的CakePHP应用程序中有2个基本模型:用户和登录。用户与登录具有hasMany关系(即,每次用户登录时都会创建新的登录记录)。

现在,我想从User模型到Login模型建立2个关系: 用户有很多登录 和 用户hasOne lastLogin

此最后一个关系应仅包括所选用户的登录模型的最后一条记录。

我尝试了如下:

var $belongsTo = array
(
    'LastLogin' => array
    (
        'className' => 'Login',
        'order' => 'LastLogin.created DESC',
        'limit' =>  1

    )
); 

然而,这不起作用。关于如何使这个工作的任何想法?

2 个答案:

答案 0 :(得分:1)

对评论作出回应的最新答案

如果关系为belongsTo,则外键应位于当前模型中。

这意味着如果您想要将User属于LastLogin的关系,users表应该有一个last_login_id字段。

在您的情况下,您可能希望使用hasOne关系,而您将不得不在MAX()键中使用fields SQL函数。请注意,获取last_login完全独立于用户hasMany登录关系。因此,如果你想要的只是最后一次登录,你可以删除hasMany关系并离开hasOne。

使用下面的示例代码,您将获得:

输出/ users / index:

Array
(
    [User] => Array
        (
            [id] => 1
            [name] => user1
            [last_login] => 2011-05-01 14:00:00
        )
    [Login] => Array
        (
            [0] => Array
                (
                    [id] => 1
                    [user_id] => 1
                    [created] => 2011-05-01 12:00:00
                )
            [1] => Array
                (
                    [id] => 2
                    [user_id] => 1
                    [created] => 2011-05-01 13:00:00
                )
            [2] => Array
                (
                    [id] => 3
                    [user_id] => 1
                    [created] => 2011-05-01 14:00:00
                )
        )
)

如果你不使用Model :: afterFind()回调,你的结果看起来会更像这样(破解登录数组以节省空间):

Array
(
    [User] => Array
        (
            [id] => 1
            [name] => user1
        )

    [0] => Array
        (
            [last_login] => 2011-05-01 14:00:00
        )
)

<小时/> 示例代码:

用户表:

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
)

登录表:

CREATE TABLE `logins` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `created` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
)

用户模型:

class User extends AppModel {
    var $name = 'User';
    var $hasMany = array('Login');
    var $hasOne = array(
        'LastLogin' => array(
            'className' => 'Login',
            'fields' => array('MAX(LastLogin.created) as last_login')
        )
    );

    // This takes the last_login field from the [0] keyed array and puts it into 
    // [User]. You could also put this into your AppModel and it would work for 
    // all find operations where you use an SQL function in the 'fields' key.
    function afterFind($results, $primary=false) {
        if (!empty($results)) {
            foreach ($results as $i => $result) {
                if (!empty($result[0])) { // If the [0] key exists in a result...
                    foreach ($result[0] as $key => $value) { // ...cycle through all its fields...
                        $results[$i][$this->alias][$key] = $value; // ...move them to the main result...
                    }
                    unset($results[$i][0]); // ...and finally remove the [0] array
                }
            }
        }
        return parent::afterFind($results, $primary=false); // Don't forget to call the parent::afterFind()
    }
}

用户控制器:

class UsersController extends AppController {
    var $name = 'Users';

    function index() {
        $this->autoRender = false;
        pr($this->User->find('all'));
    }
}

答案 1 :(得分:0)

我有类似的情况但我的是

Product hasMany Price

如果按照Product hasOne CurrentPrice按顺序排序,我希望将CurrentPrice created定义为找到的最高记录。

我用这种方式解决了我的问题。但我将改为使用你的用户和LastLogin。

class User extends AppModel {
    var $name = 'User';
    var $hasMany = array('Login');
    var $hasOne = array(
        'LastLogin' => array(
            'className' => 'Login',
            'order' => 'LastLogin.created DESC'
       )
   );

如果你考虑一下,创建和id具有相同的含义。所以你也可以按降序使用id。

我假设您的表架构与one建议的mtnorthrop类似。

CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
)
logins table:

CREATE TABLE `logins` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `created` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
)