Laravel关系避免查询外键为null的位置

时间:2016-06-12 11:20:26

标签: laravel orm laravel-5 eloquent

当急切加载时,当关系中的外键为空且因此与任何相关记录不匹配时,是否可以避免执行额外查询?在我的示例中,我有ProductUser

ProductUser所有,但也可以选择由User进行编辑。所以我的模型看起来像这样:

class Product extends Model
{
    public function user()
    {
        return $this->belongsTo(User::class);
    }

    public function editor()
    {
        return $this->belongsTo(User::class, 'editor_id');
    }
}

未对产品进行修改时,editor_id属性为NULL

如果我没有急切加载,我知道我可以做以下事情:

$product = Product::find(1);
if (!is_null($product->editor_id)) {
    // Load the relation
}

但是,这对我来说不是一个选项,我希望避免在急切加载时运行额外的,不必要的查询:

Query: select * from `users` where `users`.`id` in (?)
Bindings: [0]

我想知道是否可能出现类似以下的内容?

public function editor()
{
    if (!is_null($this->editor_id)) {
        return $this->belongsTo(User::class, 'editor_id');
    }
}

执行上述操作时,我收到此错误:

Call to a member function addEagerConstraints() on a non-object

我猜这是因为无法保证此方法返回Relation个对象。

由于

2 个答案:

答案 0 :(得分:1)

我通过创建一个实现所需方法的新Relation子类来解决这个问题,但在实际获得结果时只返回null:

namespace My\App;

use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Relations\Relation;

class NullRelation extends Relation {

    public function __construct() {}

    public function addConstraints() {}

    public function addEagerConstraints(array $models) {}

    public function initRelation(array $models, $relation) {}

    public function match(array $models, Collection $results, $relation) {
        return [];
    }

    public function getResults() {
        return null;
    }

}

然后在你的关系方法中你可以检查null并返回NullRelation的实例:

public function editor() {
    if ($this->editor_id === null) {
        return new NullRelation();
    } else {
        return $this->belongsTo(User::class, 'editor_id');
    }
}

它有点难看,而且你会重复自己很多,所以如果我在不止一个地方使用它,我可能会创建Model的子类,然后创建belongsTohasOne方法的版本并在那里执行检查:

public function belongsToIfNotNull($related, $foreignKey = null, $otherKey = null, $relation = null) {
    if ($this->$foreignKey === null) {
        return new NullRelation();
    } else {
        return parent::belongsTo($related, $foreignKey, $otherKey, $relation);
    }
}

最后,在继承新子类的模式中,您的关系方法只是

public function editor() {
    return $this->belongsToIfNotNull(User::class, 'editor_id');
}

答案 1 :(得分:0)

Laravel Docs

选择

时查询关系

访问模型的记录时,您可能希望根据关系的存在来限制结果。

 $posts= Post::has('editor')->get();

您还可以指定运算符和计数:

  $posts = Post::has('editor', '>=', 3)->get();