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

标签 php laravel eloquent

引用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();

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

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

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

我是不是搞错了什么?

最佳答案

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

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

我创建了this pull request for the Laravel docs to correct the wording.

从这样的调用生成的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 个结果。

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

关于php - Laravel Eloquent whereDoesntHave() 文档让我感到困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63064693/

相关文章:

php - header 重定向是否在不同的浏览器中产生不同的行为

php - 教义2 : Lazy loading fails and I have to re-initialize the class

php - IPN 如何将用户用户名添加到 Paypal 交易 (PHP)

javascript - Laravel Mix 和 Webpack : Cannot Load JSON File (Webpack Adding . js 到文件名)

mysql - 使用 Eloquent 获取具有 where 条件的字段总和

mysql - SQL 删除在同一事务中创建的列?

php - 在 Twig 中获取表单名称

php - 在 Laravel 中定位慢代码

php - Laravel Auth 自定义字段

php - 来自 hasMany 关系的 Laravel 预加载模型