Laravel (Lumen) Eloquent 在关系上使用 WHERE 查询(多级)

Laravel (Lumen) Eloquent querying with WHERE on a relation (Multi-level)

我有以下数据库 tables:

Purchase
-id
-workplace_id

Workplace
-id
-client_id

(显然还有更多字段,但对于示例来说,这些都是必需的)。 我想做这样的查询:

SELECT * FROM
  purchase
  INNER JOIN workplace ON (purchase.workplace_id = workplace.id)
WHERE
  (workplace.client_id = 1)

我正在尝试使用 Eloquent 模型进行这项工作,但我不知道如何在连接的 table 上进行过滤。 我试过了:

    $purchases = Purchase::query()
        -> workplace()
        -> where('client_id', '=', Auth::user() -> client_id)
        -> get();

但显然 workplace() 由于某种原因未定义。

我的 Purchase.php 模型文件如下所示:

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Purchase extends Model
{
    public function workplace(): \Illuminate\Database\Eloquent\Relations\BelongsTo
    {
        return $this->belongsTo(Workplace::class);
    }
}

关于如何使这个简单的 select 工作的任何指示?

谢谢!

====编辑=====

我找到了一个可能的解决方案:

    $purchases = Purchase::with('workplace')
        -> whereHas('workplace', function($q) {
            return $q -> where('client_id', '=', Auth::user() -> client_id);
        })
        -> get();

但这会生成一个 SQL,它看起来更复杂并且可能也更慢:

select * from `purchases` where exists (select * from `workplaces` where `purchases`.`workplace_id` =
`workplaces`.`id` and `client_id` = ? and `workplaces`.`deleted_at` is null)

所以我还在寻找更好的替代品

如果你想做一个连接,你需要用join方法建立它,你不能使用关系。请在此处查看文档:

https://laravel.com/docs/9.x/queries#joins

所以你应该可以这样做:

$purchases = Purchase::query()
    ->join('workplace', 'purchase.workplace_id', '=', 'workplace.id')
    ->where('workplace.client_id', '=', Auth::user()->client_id)
    ->get();

您在编辑中显示的生成的 SQL 是 sub-query,您可能仍要考虑这一点。当然,sub-queries 通常比联接慢,但除非您处理的是海量数据集,否则性能差异可能可以忽略不计,并且它允许您使用本机 Eloquent 关系。

有关此问题的讨论,请参见此处: