有没有办法将表名自动添加到 Eloquent 查询方法中?
我正在 Laravel 5.5 上开发一个应用,并且遇到了一个特定查询范围的问题。我有下面的表格结构(省略了一些字段):
orders
---------
id
parent_id
status
该列引用来自同一表的 。我有这个查询范围来筛选没有任何子项的记录:parent_id
id
public function scopeNoChildren(Builder $query): Builder
{
return $query->select('orders.*')
->leftJoin('orders AS children', function ($join) {
$join->on('orders.id', '=', 'children.parent_id')
->where('children.status', self::STATUS_COMPLETED);
})
->where('children.id', null);
}
此作用域在单独使用时工作正常。但是,如果我尝试将其与任何其他条件组合在一起,则会引发 SQL 异常:
Order::where('status', Order::STATUS_COMPLETED)
->noChildren()
->get();
导致这种情况:
SQLSTATE[23000]:完整性约束冲突:1052 子句不明确的列“状态”
我找到了两种方法来避免这种错误:
解决方案#1:在所有其他条件前面加上表名
执行如下操作有效:
Order::where('orders.status', Order::STATUS_COMPLETED)
->noChildren()
->get();
但我不认为这是一个好方法,因为不清楚表名是否需要,以防其他开发人员甚至我自己将来再次尝试使用该范围。他们可能最终会弄清楚这一点,但这似乎不是一个好的做法。
解决方案#2:使用子查询
我可以在子查询中将不明确的列分开。不过,在这种情况下,随着表的增长,性能会降低。
不过,这就是我使用的策略。因为它不需要对其他范围和条件进行任何更改。至少不是我现在应用它的方式。
public function scopeNoChildren(Builder $query): Builder
{
$subQueryChildren = self::select('id', 'parent_id')
->completed();
$sqlChildren = DB::raw(sprintf(
'(%s) AS children',
$subQueryChildren->toSql()
));
return $query->select('orders.*')
->leftJoin($sqlChildren, function ($join) use ($subQueryChildren) {
$join->on('orders.id', '=', 'children.parent_id')
->addBinding($subQueryChildren->getBindings());
})->where('children.id', null);
}
完美的解决方案
我认为能够在不以表名为前缀的情况下使用查询而不依赖于子查询将是完美的解决方案。
这就是为什么我要问:有没有办法让表名自动添加到 Eloquent 查询方法中?