mpyw/eloquent-has-by-non-dependent-subquery

此包已被废弃,不再维护。未建议替代包。

将 has() 和 whereHas() 约束转换为非依赖子查询。

v2.0.3 2022-07-14 19:22 UTC

This package is auto-updated.

Last update: 2023-11-21 17:27:45 UTC


README

has()whereHas() 约束转换为非依赖子查询。

重要

注意:Postgres 的优化器非常智能,涵盖了依赖(相关)子查询的 JOIN 优化。因此,这个库主要针对 MySQL,其优化器性能较差。

注意

更新:MySQL 的优化器也在版本 8.0.16 中更新,包括类似于 PostgreSQL 的优化。 此库不再维护。

要求

  • PHP: ^7.3 || ^8.0
  • Laravel: ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0

安装

composer require mpyw/eloquent-has-by-non-dependent-subquery

建议

您可以使用 wimski/laravel-ide-helper-hook-eloquent-has-by-non-dependent-subqueryLaravel IDE Helper 一起使用。

动机

假设您有以下关系

class Post extends Model
{
    use SoftDeletes;

    public function comments(): HasMany
    {
        return $this->hasMany(Comment::class);
    }
}
class Comment extends Model
{
    use SoftDeletes;
}

如果您使用 has() 约束,您的实际查询将会有 依赖子查询

$posts = Post::has('comments')->get();
select * from `posts` where exists (
  select * from `comments`
  where `posts`.`id` = `comments`.`post_id`
    and `comments`.`deleted_at` is null
) and `posts`.`deleted_at` is null

这些子查询可能会导致性能下降。此包提供了 Illuminate\Database\Eloquent\Builder::hasByNonDependentSubquery() 宏来解决这个问题:您可以轻松地将依赖子查询转换为非依赖子查询。

$posts = Post::hasByNonDependentSubquery('comments')->get();
select * from `posts`
where `posts`.`id` in (
  select `comments`.`post_id` from `comments`
  where `comments`.`deleted_at` is null
)
and `posts`.`deleted_at` is null

API

签名

Illuminate\Database\Eloquent\Builder::hasByNonDependentSubquery(string|string[] $relationMethod, ?callable ...$constraints): $this
Illuminate\Database\Eloquent\Builder::orHasByNonDependentSubquery(string|string[] $relationMethod, ?callable ...$constraints): $this
Illuminate\Database\Eloquent\Builder::doesntHaveByNonDependentSubquery(string|string[] $relationMethod, ?callable ...$constraints): $this
Illuminate\Database\Eloquent\Builder::orDoesntHaveByNonDependentSubquery(string|string[] $relationMethod, ?callable ...$constraints): $this

参数

$relationMethod

一个返回 Relation 实例的关系方法名称,除了 MorphTo

Builder::hasByNonDependentSubquery('comments')

您可以通过数组或点链式语法传递嵌套关系。

Builder::hasByNonDependentSubquery(['comments', 'author'])
Builder::hasByNonDependentSubquery('comments.author')

$constraints

为接受 Illuminate\Database\Eloquent\Relation 作为第一个参数的关系提供的额外 callable 约束。

Builder::hasByNonDependentSubquery('comments', fn (HasMany $query) => $query->withTrashed())

如果您从 PHP 8.0 开始使用联合类型,则类型顺序无关紧要。

// This will work
Builder::hasByNonDependentSubquery('comments', fn (HasMany|Comment $query) => $query->withTrashed())
// and so will this
Builder::hasByNonDependentSubquery('comments', fn (Comment|HasMany $query) => $query->withTrashed())

第一个闭包对应于 comments,第二个闭包对应于 author

Builder::hasByNonDependentSubquery(
    'comments.author',
    fn (HasMany $query) => $query->withTrashed(),
    fn (BelongsTo $query) => $query->whereKey(123)
)

功能比较

功能 mpyw/eloquent-has-by-join mpyw/eloquent-has-by-non-dependent-subquery
最低 Laravel 版本 5.6 5.8
可选约束的参数 Illuminate\Database\Eloquent\Builder Illuminate\Database\Eloquent\Relations\*
(Builder 也可以通过指定参数类型接受)
Compoships 支持
无子查询
(性能取决于数据库优化器)
无表冲突
(有时需要指定别名)
无列冲突
(有时需要使用限定列名)
OR 条件
否定条件
计数条件
HasOne
HasMany
BelongsTo
BelongsToMany
MorphOne
MorphMany
MorphTo
MorphMany
MorphToMany
HasOneThrough
HasManyThrough