在 Laravel Eloquent 中获取和过滤关系

Posted

技术标签:

【中文标题】在 Laravel Eloquent 中获取和过滤关系【英文标题】:Fetching and filtering relations in Laravel Eloquent 【发布时间】:2015-04-10 18:01:00 【问题描述】:

我在 Eloquent 中有以下模型:组、线程、cmets 和用户。我想从特定用户中找到特定组中的所有 cmets。

这是我目前的做法:

$group->threads->each(function ($thread) use ($user_id)

  $user_comments = $thread->comments->filter(function ($comment) use ($user_id)
  
    return $comment->owner_id == $id;
  );
);

这看起来丑得要命,可能慢得要命,我只想摆脱它。在 Eloquent 中获取我的结果集的最快、最优雅的方式是什么?

【问题讨论】:

您想将所有 cmets 合并还是逐个线程? 我真的不在乎。所有的 cmets 组合起来就足够了。 你们的关系怎么样?因为如果您正确设置了关系,您可以执行类似 $group->find(1)->users()>find(1)->cmets; 【参考方案1】:

如果group hasMany threadsthread hasMany comments,您可以向组添加另一个关系:group hasMany commentsthreads

在群里:

public function comments() 
    return $this->hasManyThrough('Comment', 'Thread');

现在,您可以通过$group->comments;获取群组中的cmets

从这里,您可以满足用户的需求:

$user_comments = $group->comments()->where('owner_id', $user_id)->get();

如果需要,您可以将 where 提取到 Comment 的范围内。

【讨论】:

【参考方案2】:

patricus 解决方案为我指明了正确的方向。我将我的问题交叉发布到laracasts Forum,并从Jarek Tkaczyk 那里得到了很多帮助,Jarek Tkaczyk 也经常访问这个网站。

hasManyThrough() Group 模型是要走的路:

public function comments()

  return $this->hasManyThrough('ThreadComment', 'Thread');

不过有几点需要注意:

    使用关系对象而不是集合($group->comments()NOT $group->comments) 如果你使用 Laravel 的软删除,你不能只将 get() 更改为 delete(),因为你会得到 updated_at 列的歧义错误。你也不能加前缀,这就是 Eloquent 的工作原理。

如果您想从特定组中的特定用户中删除所有 cmets,您必须做一些不同的事情:

$commentsToDelete = $group->comments()
        ->where('threads_comments.owner_id', $id)
        ->select('threads_comments.id')
        ->lists('id');

ThreadComment::whereIn('id', $commentsToDelete)->delete();

您基本上在第一个查询中获取所有相关 ID,然后在第二个查询中批量删除它们。

【讨论】:

区分关系对象 () 和集合,只是大多数关系问题的答案。谢谢!!

以上是关于在 Laravel Eloquent 中获取和过滤关系的主要内容,如果未能解决你的问题,请参考以下文章

从父多对多关系获取所有子模型 Laravel Eloquent

从 eloquent builder laravel 7 获取关系数据

Laravel cviebrock/eloquent-sluggable 将 @ 作为前缀或在路由中过滤它

使用 Eloquent 在 Laravel 中使用 where 子句访问嵌套的相关对象

Laravel 5 - Eloquent:过滤多种关系的简单方法

Laravel 5 / Eloquent - 对属于多的关系进行查询过滤