通过 Laravel 关系查询 HasManyThrough 检索相关记录

Posted

技术标签:

【中文标题】通过 Laravel 关系查询 HasManyThrough 检索相关记录【英文标题】:Query HasManyThrough Laravel relation retrieving related records 【发布时间】:2017-11-18 14:28:34 【问题描述】:

考虑到 Laravel 指南中的基本示例 Has Many Through 关系,我尝试直接查询具有 100 类型帖子的雄辩的国家(只是一个示例)。

countries
    id - integer
    name - string

users
    id - integer
    country_id - integer
    name - string

posts
    id - integer
    user_id - integer
    title - string
    type_id - integer

posts 中的 type_id 是我的特殊情况..

因此,我在国家模型中创建了一个关系,该关系通过用户创建了与帖子的关系。我想要实现的结果是一个国家列表以及每个国家/地区内该国家/地区用户创建的帖子。

//Country.php
public function posts()

    return $this->hasManyThrough(
        'Post', 'User', 'country_id', 'user_id'
    );

我能够以其他方式复制我想要达到的结果,但我想知道为什么下面的雄辩查询没有返回预期的结果:

   $postsGroupedByCountries = Country::with([
        'posts' => function ($query) 
            $query->where('type_id', 100);
        
    ])->get();

查询的返回是几个国家,所有帖子都没有数据。使用 Laravel Eloquent 进行此查询的正确方法是什么?

第一次尝试:

$postsGroupedByCountries = Country::whereHas('posts', function ($query) 
    $query->where('type_id', 100);
)->get();

第二次尝试:

$postsGroupedByCountries = Country::whereHas('posts', function ($query) 
    $query->where('type_id', 100)->groupBy('posts.id');
)->get();

第三次尝试:

$postsGroupedByCountries = Country::whereHas('posts', function ($query) 
    $query->where('type_id', 100);
)->get();

$postsGroupedByCountries = $postsGroupedByCountries ->map(function($country)
     $country->load('posts');
     return $country;
);

而且我已经尝试在负载内部使用带有 where 的闭包。但它也没有奏效。结果是一样的。

【问题讨论】:

【参考方案1】:

您急于加载每个国家/地区的所有帖子,这就是您看到所有帖子的原因。我会尝试将查询修改为:

$postsGroupedByCountries = Country::whereHas('posts', function ($query) 
    $query->where('type_id', 100)
)->get();

看看你得到了什么回报。

【讨论】:

但我想提供加载帖子的数据。哪里会做呢?我认为 whereHas 只是条件。 我认为它会将加载的帖子返回给您,试一试,看看结果如何。我一直在参考这篇文章,顺便说一句:***.com/questions/30231862/… 帖子未加载。我猜想 where has 是延迟加载。我需要在雄辩的查询之后进行 foreach 并调用 $country->posts 来获取它并放入国家/地区。 使用之后,如果我尝试访问它的关系 ($country->posts),我会得到与第一次尝试相同的结果。很多不连贯的帖子。 尝试将 groupBy 添加到嵌套查询中,例如:$query->where('type_id', 100)->groupBy('posts.id')【参考方案2】:

您必须使用withwhereHas 进行查询。 whereHas 将限制 Country 查询仅显示具有指定 id 帖子的国家,但不会在结果中加载这些帖子。然后with() 将在结果中急切加载posts,但是因为它在第一个查询执行后被调用,它不知道whereHas 约束,并且由于它没有通过任何约束,它将加载所有帖子各国。要使用相同的约束加载 Country 的帖子,您还需要将其传递给 with 方法。

所有放在一起看起来像:

$countries = Country::whereHas('posts', function($query) 
    return $query->where('type_id', 100);
)
->with(['posts' => function($query) 
    return $query->where('type_id', 100);
])
->get();

【讨论】:

以上是关于通过 Laravel 关系查询 HasManyThrough 检索相关记录的主要内容,如果未能解决你的问题,请参考以下文章

通过 Laravel 关系查询 HasManyThrough 检索相关记录

Laravel 通过属性获得雄辩的查询构建器关系

通过 id 获取记录并使用 Laravel 和 eloquent 查询与“中间”的关系

Laravel - 如何通过关系来执行where查询?

Laravel 多对多关系查询

Laravel 4 关系数据库查询