【问题标题】:Laravel Eloquent - Do not run relationship query if column value is NULL or 0Laravel Eloquent - 如果列值为 NULL 或 0,则不运行关系查询
【发布时间】:2017-11-25 17:59:00
【问题描述】:

我的EloquentModels 中有各种关系,如下所示:

public function main_image()
{
    return $this->hasOne(Media::class, 'id', 'main_image_id');
}

但是,如果main_image_id 为 null 或 0,它将运行 SQL 查询,所以我最终会得到许多这样的查询:

select * from `media` where `media`.`id` is null and `media`.`id` is not null limit 1

这显然不会返回任何东西,但仍然浪费资源。有什么方法可以自动检查吗?

目前我所做的是有一个方法,比如hasMainImage(),它检查main_image_id 不为空也不为0,但是当前的很多系统已经使用了这些关系,我想知道是否可以添加检查关系方法本身?

我尝试向它添加检查并返回null,如果该列没有实际值,但我有一个Exception,它必须返回一个关系对象。或者,如果我尝试 Eager 加载它,我会收到以下错误:

Call to a member function addEagerConstraints() on null

public function main_image()
{
    if (!$this->main_image_id) {
        return null;
    }

    return $this->hasOne('App\Modules\Media\Models\Media', 'id', 'main_image_id');
}

感谢您的帮助!

编辑: 一个也许更清楚的例子:

$page = Page::find(1);
var_dump($page->main_image); // This will run a query as shown above that is guaranteed to return nothing
// Since at this point system knows that $page->main_image_id is 0 or null, I would like to use that to not run the query and automatically set $page->main_image to null

【问题讨论】:

  • 执行with 会使用额外的资源。你不应该一开始就这样做,也不应该到处都这样做,然后试图绕过它。
  • with 并非在任何地方使用,仅在一次加载多个模型的情况下使用。当仅加载单个实例时,不使用with,并进行$page->main_image 之类的调用。这些是我在这里尝试优化的调用
  • 这样做没有额外的好处。无论哪种方式加入都会发生,它只会返回更少的东西。我当然假设你在这里是一对一的关系。
  • 我的目标不是运行 SQL 查询,当我知道 $page->main_image_id0null 时,我正在执行类似 $page->main_image 的调用。我需要在模型的方法级别进行检查。
  • 如果您渴望加载,那么 $page->main_image 不会/不应触发单个查询。查询是在整个结果集上抢先完成的。

标签: php mysql laravel eloquent


【解决方案1】:

你以错误的顺序声明你的关系,Eloquent documentation 很清楚这一点。

本身没有意义的实体(你可能会说没有它的“父”)应该包含“belongsTo”关系(正如文档所说的相反)。

为了演示,假设您有用户模型,并且您有关于该用户的许多详细信息,因此您创建了详细信息模型。

现在用户模型应该有详细关系:

public function detail() {
    return $this->hasOne('App\Detail', 'user_id', 'id'); //you can see the difference here from your code sample, you have 2nd and 3rd parameter reversed
}

并且Detail模型应该有用户关系:

public function user()
{
    return $this->belongsTo('App\User');
}

【讨论】:

  • 这不是我目前拥有的结构。我有Page 模型和Media 模型。 Media 模型是一个自包含模型,不附属于任何其他模型(因为它可以被不同的模型和模型实例多次使用)。 Page 有一个 main_image 方法(定义在 quetstion 中),它定义了与 Media 的关系。如果我事先知道它不会返回任何内容,我不想运行 SQL 查询。我不确定在Media 模型中定义belongsTo 是如何解决这个问题的?无论哪种方式,我都不需要从 Media 实例中访问任何其他模型。
  • 在这种情况下不是。 Page 模型可以有一个 Media 与其关联为main_image,但是,相同的Media 模型可以与其他页面关联为main_image,以及许多其他模型作为不同类型的图像.所以Page“有一个”媒体对象,在pages 表中引用为main_image_id。我想知道我是否应该在这里使用belongsTo 关系?以及这是否会对运行查询产生任何影响?我假设它会运行我想要摆脱的 SQL 查询,因为那里可能有一个 0。
  • 我现在明白你关于错误顺序的意思了。但是,我已将hasOne 切换为belongsTo,这对查询和我在这里尝试解决的问题没有任何影响。
  • @Giedrius 演示您如何访问相关实体。
  • @Giedrius 嘿,好消息github.com/laravel/framework/pull/19733 监控该 PR,如果它合并,您可以使用 ->withDefault() 并设置“空”关系,不确定它是否会出现在桌面上,但它的东西这将对您的情况有所帮助。
猜你喜欢
  • 2014-12-10
  • 2013-10-03
  • 2017-07-19
  • 2018-10-22
  • 2021-09-25
  • 2015-01-21
  • 2017-01-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多