Laravel 5.3 使用 with() 方法预先加载关系

Posted

技术标签:

【中文标题】Laravel 5.3 使用 with() 方法预先加载关系【英文标题】:Laravel 5.3 eager loaded relations using method with() 【发布时间】:2017-04-23 18:34:07 【问题描述】:

我对使用 with() 方法的 Laravel 5.3 急切加载的关系有疑问。

要么我做错了,要么我理解错了。

我运行这段代码:

$result = Post::with(['cmets' => function ($query) $query->where('content', 'like', '"%blanditiisx%"'); ])->get();

通过根据经验检查数据库表“cmets”,我知道只有一条评论在其“内容”列中包含“blanditiisx”一词。

因此,由于给定的评论只能属于一篇帖子,而我们只有一条符合“where”条件的评论,所以我希望只获得一篇帖子。

令我惊讶的是,上面的代码返回了我在数据库中的所有帖子。

如果有人能告诉我哪里出了问题,我将不胜感激。


这是我的工作:


发布

我有 Post 类,其中定义了这种关系:

/** * 一对多关系 * * @return \Illuminate\Database\Eloquent\Relations\hasMany */ 公共函数 cmets() 返回 $this->hasMany(Comment::class);

它适用于这个帖子表:

+------------+------------------+------+-----+---- -----+----------------+ |领域 |类型 |空 |钥匙 |默认 |额外 | +------------+------------------+------+-----+---- -----+----------------+ |编号 | int(10) 无符号 |否 |优先级 |空 |自动增量 | | created_at |时间戳 |是 | |空 | | |更新时间 |时间戳 |是 | |空 | | |标题 | varchar(255) |否 | |空 | | |蛞蝓 | varchar(255) |否 |统一 |空 | | |总结 |正文 |否 | |空 | | |内容 |正文 |否 | |空 | | |见过|小整数(1) |否 | | 0 | | |活跃 |小整数(1) |否 | | 0 | | |用户 ID | int(10) 无符号 |否 |穆尔 |空 | | +------------+------------------+------+-----+---- -----+----------------+

评论

我有 Comment 类,其中定义了这种关系:

/** * 一对多关系 * * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ 公共功能 post() 返回 $this->belongsTo(Post::class);

它适用于这个 cmets 表:

+------------+------------------+------+-----+---- -----+----------------+ |领域 |类型 |空 |钥匙 |默认 |额外 | +------------+------------------+------+-----+---- -----+----------------+ |编号 | int(10) 无符号 |否 |优先级 |空 |自动增量 | | created_at |时间戳 |是 | |空 | | |更新时间 |时间戳 |是 | |空 | | |内容 |正文 |否 | |空 | | |见过|小整数(1) |否 | | 0 | | |用户 ID | int(10) 无符号 |否 |穆尔 |空 | | | post_id | int(10) 无符号 |否 |穆尔 |空 | | |删除_at |时间戳 |是 | |空 | | +------------+------------------+------+-----+---- -----+----------------+

编辑:

实际上我的初始代码有效,它只是以一种让我感到困惑的方式返回结果。

它的作用是为每个帖子返回一个集合。

大部分都是空的。只有那些属于查询约束的集合才会填充数据。

其余部分是空的,但仍被提取,因此可以使用 count() 将它们过滤掉。

当然,他们很渴望。

【问题讨论】:

【参考方案1】:

你可以试试whereHas()

$result = Post::whereHas('comments', function ($query) 

    $query->where('content', 'like', '"%blanditiisx%"');

)->with('comments')->get();

它允许向关系约束添加自定义约束,例如检查评论的内容。

或者试试:

Post::whereHas('comments', function ($query) 
            $query->where('content', 'like', '"%blanditiisx%"');
        )
        ->with(['comments' => function ($query) 
            $query->where('content', 'like', '"%blanditiisx%"');
        ])
        ->get();

Docs

【讨论】:

我知道 has()/whereHas() 有效,但它仍然会被急切加载吗? 不,这就是我在查询中添加with('comments') 的原因。但是,如果您只想获得过滤后的评论,请在其中添加 where 约束。 你可以使用whereHaswith的组合得到结果。 那么,你在说什么,通过与('cmets') 链接,我会急切地加载它,对吧? ----- 至于我的(不工作示例) - 在 Laravel 文档laravel.com/docs/5.3/eloquent-relationships#one-to-many 中,如果您在该页面上找到“约束急切负载”,您会发现:“有时您可能希望急切加载关系,但也为急切加载查询指定额外的查询约束。”——因此似乎暗示应该可以精细化查询。他们甚至举了我的例子——这没有用。 感谢您的宝贵时间。我很感激。你的回答只是把我推向了正确的方向。实际上我的初始代码有效,它只是以一种让我感到困惑的方式返回结果。它的作用是为每个帖子返回一个集合。其中大部分是空的。只有那些属于查询约束的集合才会填充数据。其余部分是空的,但仍被提取,因此可以使用 count() 将它们过滤掉。当然,他们很渴望。再次感谢。【参考方案2】:

with() 方法用于预加载相关数据,而不是过滤您已有的查询。请参阅 whereHas() 方法了解您要查找的过滤。

【讨论】:

根据 Laravel 文档laravel.com/docs/5.3/eloquent-relationships#one-to-many,如果您在该页面上找到“约束急切负载”,您会发现类似的示例并说明:“有时您可能希望急切加载关系,但也指定急切加载查询的附加查询约束。“ - 因此似乎表明,应该可以精细化查询。 这限制了“急切加载查询”。在您的示例中,这意味着限制您要加载的 cmets。您似乎希望它限制将加载哪些帖子。这就是 whereHas() 的用途。

以上是关于Laravel 5.3 使用 with() 方法预先加载关系的主要内容,如果未能解决你的问题,请参考以下文章

Gorm 预加载及实现联表条件查询仿WhereHas

Gorm 预加载及实现联表条件查询仿WhereHas

Laravel 用户模型条件预加载(带)

Laravel 5.3 保护下载文件的正确方法

在 Laravel 5.3 项目中使用 PHPUnit 存根类方法调用的问题

如何在不使用请求的情况下删除 Laravel 5.3 中的会话?