猿问

Laravel Eloquent whereDoesntHave() 文档让我感到困惑

参考https://laravel.com/docs/7.x/eloquent-relationships#querying-relationship-absence查询


use Illuminate\Database\Eloquent\Builder;


$posts = App\Post::whereDoesntHave('comments.author', function (Builder $query) {

    $query->where('banned', 0);

})->get();

被描述为“检索所有带有未被禁止的作者评论的帖子”。这对我来说似乎是不正确的,因为这似乎意味着,如果一篇文章有来自被禁止作者的一条评论和来自非被禁止作者的另一条评论,那么该帖子将出现在结果集合中 - 毕竟,它有来自被禁止作者的评论没有禁止。


实际上,由于存在被禁止的作者的评论,这样的帖子不会被包含在集合中,无论该帖子可能有其他评论如何。


似乎更准确的说法是“检索所有有评论的帖子,其中没有一个来自被禁止的作者”。


我是不是弄错了什么?


泛舟湖上清波郎朗
浏览 140回答 1
1回答

ITMISS

事实上,两者都不正确。正确的说法是:“检索所有没有评论的帖子,或者所有评论都来自被禁止的作者”我为 Laravel 文档创建了这个拉取请求来更正措辞。从这样的调用生成的 sql 将如下所示:SELECT     *FROM    `posts`WHERE    NOT EXISTS( SELECT             *        FROM            `comments`        WHERE            `posts`.`id` = `comments`.`postId`                AND EXISTS( SELECT                     *                FROM                    `authors`                WHERE                    `comments`.`authorId` = `authors`.`id`                        AND `banned` = 0))细分一下,内部查询说“找到与每个帖子相关的所有评论,其中该评论是由未被禁止的作者撰写的。            SELECT                 *            FROM                `comments`            WHERE                `posts`.`id` = `comments`.`postId`                    AND EXISTS( SELECT                         *                    FROM                        `authors`                    WHERE                        `comments`.`authorId` = `authors`.`id`                            AND `banned` = 0)然后,顶级查询说:“现在,给我上面子查询没有返回行的所有帖子”即,所有作者都被禁止,或者根本没有评论。  SELECT         *    FROM        `posts`    WHERE        NOT EXISTS(          {.. sub query above here }       )如果你想自己测试一下,楷模:<?phpnamespace App\Models;use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\HasMany;class Post extends Model{    public function comments(): HasMany    {        return $this->hasMany(Comment::class, 'postId');    }}<?phpnamespace App\Models;use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\HasOne;class Comment extends Model{    public function author(): HasOne    {        return $this->hasOne(Author::class, 'id', 'authorId');    }}<?phpnamespace App\Models;use Illuminate\Database\Eloquent\Model;class Author extends Model{}创建表Sql:CREATE TABLE `posts` (    `id` BIGINT NOT NULL AUTO_INCREMENT,    PRIMARY KEY (`id`));CREATE TABLE `comments` (    `id` BIGINT(20) NOT NULL AUTO_INCREMENT,    `postId` BIGINT(20) NOT NULL,    `authorId` BIGINT(20) NOT NULL,    `content` VARCHAR(50) NOT NULL,    PRIMARY KEY (`id`));CREATE TABLE `authors` (    `id` BIGINT(20) NOT NULL AUTO_INCREMENT,    `name` VARCHAR(50) NOT NULL,    PRIMARY KEY (`id`));内容sql:# crate a postINSERT INTO `posts` (`id`) VALUES ('1');# add a banned and not banned author INSERT INTO `authors` (`name`, `banned`) VALUES ('Jack', '0');INSERT INTO `authors` (`name`, `banned`) VALUES ('Jill', '1');# add a comment from a banned and not banned author INSERT INTO `comments` (`postId`, `authorId`, `content`) VALUES ('1', '1', 'a');INSERT INTO `comments` (`postId`, `authorId`, `content`) VALUES ('1', '2', 'b');现在运行代码:$post = \App\Models\Post::whereDoesntHave('comments.author', function ( $query) {     $query->where('banned', 0);})->get();您将得到 0 个结果。现在运行此命令以使两位作者都不会被禁止:UPDATE `authors` SET `banned`='0';您仍然会得到 0 个结果。现在运行这个命令来禁止两位作者:UPDATE `authors` SET `banned`='1';您现在将返回 1 个结果。现在运行此命令,使两位作者不再被禁止,但删除他们的评论:UPDATE `authors` SET `banned`='0';DELETE FROM `comments`;您现在将返回 1 个结果。这证明实际行为是“检索所有没有评论的帖子,或者所有评论都来自被禁止的作者”
随时随地看视频慕课网APP
我要回答