【问题标题】:Laravel eloquent apply whereHas on latest record of hasMany relationshipLaravel eloquent apply whereHas on the latest record of hasMany 关系
【发布时间】:2020-10-02 15:57:43
【问题描述】:

使用 Laravel 7.0

我有 3 个模型(MeetingMeetingVersionUser), 和 4 个表格(Meetingmeeting_versionsusersmeeting_versions_users)。

一个Meeting有很多MeetingVersion模型,其中每个版本都与Usermany-to-many关系。每个 MeetingVersion 都有一个指向其父 Meeting 的外键 meeting_id。用户通过 meeting_versions_users 数据透视表关联到一个 MeetingVersion。

现在,我想选择最新版本与给定用户 ID 相关联的所有会议。

会议课

public function versions()
{
    return $this->hasMany(MeetingVersion::class, 'meeting_id');
}

MeetingVersion 类

public function users()
{
    return $this->belongsToMany(User::class, 'meeting_versions_users', 'version_id', 'user_id');
}

表格

会议

+----+
| id |
+----+
| 10 |
| 11 |
+----+

meeting_versions

+----+------------+---------+
| id | meeting_id | version |
+----+------------+---------+
| 31 |         10 |       1 |
| 32 |         10 |       2 |
| 33 |         10 |       3 | <- latest version (33) for meeting id 10
| 34 |         11 |       1 |
| 35 |         11 |       2 | <- latest version (35) for meeting id 11
+----+------------+---------+

meeting_versions_users

+------------+---------+
| version_id | user_id |
+------------+---------+
|         31 |     101 |
|         32 |     101 |
|         33 |     102 | <- user associated with latest version for meeting id 10
|         34 |     101 |
|         35 |     101 | <- user associated with latest version for meeting id 11
+------------+---------+

用户

+-----+
| id  |
+-----+
| 101 |
| 102 |
+-----+

这是我正在尝试的查询。我应该只返回会议 11,但此查询返回用户 101 的两个会议。

// Some user id.
$userId = 101;


// Query to get all meetings where user is associated with latest version of meeting.

$meeting = Meeting::query()->where(function (Builder $query) use ($userId) {

        $query->whereHas('versions', function (Builder $query) use ($userId) {

            /*
             * I want to get just the "latest" version model here, so that further queries are constrained to that model only.
             * As it is now, the below whereHas query is applied to all child models.
             * Using $query->latest('version')->limit(1) doesn't work here as expected.
             *
             * So, I need to a way to limit the following whereHas query to the latest version.
             * This constraint should be applied to just the "latest" model relation, instead of all models.
            */

            $query->whereHas('users', function (Builder $query) use ($userId) {
                $query->where('id', $userId);
            });

        });
    })->get();

非常感谢任何帮助。

【问题讨论】:

    标签: laravel eloquent laravel-query-builder eloquent-relationship laravel-7.x


    【解决方案1】:

    在你的问题中你说:

    • 在此处使用 $query->latest('version')->limit(1) 无法按预期工作。

    因为 laravel 得到了整个查询的最后一个 MeetingVersion!不是每次会议

    解决这个问题使用eloquent-eager-limit

    安装它:

    composer require staudenmeir/eloquent-eager-limit:"^1.0"
    

    然后在会议模型中:

    class Meeting extends Model
    {
    use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;
    .....
    public function lastMeetingVersion()
    {
    return $this->hasMany(MeetingVersion::class, 'meeting_id')
    ->orderBy('id','desc')->limit(1);
    }
        }
    

    在 MeetingVersion 中:

    class MeetingVersion extends Model
    {
    use \Staudenmeir\EloquentEagerLimit\HasEagerLimit;
    ......
    }
    

    现在限制将按您的预期工作......

    $meeting = Meeting::query()->with(['lastMeetingVersion' => function ($query)
            use ($userId) {
                $query->whereHas('users', function ($q) use ($userId) {
                    $q->where('id', $userId);
                });
            }]);
    

    更多详情请见:eloquent-eager-limit

    【讨论】:

    • 谢谢,OMR。我尝试了这个解决方案,但我也没有工作。在此查询的末尾添加-&gt;get() 时,出现内存已耗尽错误。我也只是尝试使用-&gt;find(10),它返回一个结果,但对两个用户都这样做,而不是用户用户 102。
    【解决方案2】:

    您可以使用 subselect 来获取每个会议的最大版本 ID。

    $meetings = Meeting::query()
        ->whereHas('versions', function (Builder $query) use ($userId) {
            $query->addSelect([
                'max_meeting_version_id' => MeetingVersion::select('id')->whereColumn('meeting_id', 'meeting.id')
                    ->orderBy('version', 'desc')->limit(1)
            ])->whereHas('users', function (Builder $query2) use ($userId) {
                $query2->where('users.id', $userId);
            })
                ->havingRaw('max_meeting_version_id = meeting_versions.id');
        })
        ->get();
    

    【讨论】:

    • 谢谢,邦诺基亚。我试过这个,但在havingRaw 子句中出现错误。 “未找到列:1054 Unknown column 'meeting_versions.id' in 'have Clause'” 我尝试将子句更改为 'max_meeting_version_id = id',从而防止出现错误。但是,现在它没有产生任何结果。
    • 你有 laravel 调试栏吗,它可以显示原始的 sql 查询。我不确定为什么meeting_versions.id 不知道。
    猜你喜欢
    • 2016-08-13
    • 2020-12-23
    • 2016-03-17
    • 2021-05-25
    • 2018-06-19
    • 2020-03-25
    • 2016-09-05
    • 2020-06-12
    • 2015-12-22
    相关资源
    最近更新 更多