为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

PHP
泛舟湖上清波郎朗 2023-08-26 10:12:27
参考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();被描述为“检索所有带有未被禁止的作者评论的帖子”。这对我来说似乎是不正确的,因为这似乎意味着,如果一篇文章有来自被禁止作者的一条评论和来自非被禁止作者的另一条评论,那么该帖子将出现在结果集合中 - 毕竟,它有来自被禁止作者的评论没有禁止。实际上,由于存在被禁止的作者的评论,这样的帖子不会被包含在集合中,无论该帖子可能有其他评论如何。似乎更准确的说法是“检索所有有评论的帖子,其中没有一个来自被禁止的作者”。我是不是弄错了什么?
查看完整描述

1 回答

?
ITMISS

TA贡献1871条经验 获得超8个赞

事实上,两者都不正确。正确的说法是:

“检索所有没有评论的帖子,或者所有评论都来自被禁止的作者”

我为 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 }

       )

如果你想自己测试一下,

楷模:


<?php


namespace 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');

    }

}



<?php


namespace 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');

    }


}


<?php


namespace 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 post

INSERT 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 个结果。


这证明实际行为是“检索所有没有评论的帖子,或者所有评论都来自被禁止的作者”


查看完整回答
反对 回复 2023-08-26
  • 1 回答
  • 0 关注
  • 139 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信