Laravel-通过数据透视表的一对一关系

Laravel-通过数据透视表的一对一关系,laravel,eager-loading,Laravel,Eager Loading,我有这种关系 一个运动可以有多个步骤 一步可以属于多次运动 因此a必须创建一个透视表和一个belongToMany关系,但是我的透视表有一些额外的列,比如finished和order 我想有两个关系,一个是从一个动作中获取所有步骤,另一个是从该动作中获取当前步骤(最后完成的步骤) 我知道如何获得所有步骤 public function steps() { return $this->belongsToMany(MovementStep::class, 'movement_mov

我有这种关系

  • 一个运动可以有多个步骤
  • 一步可以属于多次运动
因此a必须创建一个透视表和一个
belongToMany
关系,但是我的透视表有一些额外的列,比如
finished
order

我想有两个关系,一个是从一个动作中获取所有步骤,另一个是从该动作中获取当前步骤(最后完成的步骤)

我知道如何获得所有步骤

public function steps()
{
    return $this->belongsToMany(MovementStep::class, 'movement_movement_steps')
        ->withPivot('order', 'finished')
        ->orderBy('pivot_order');
}
但目前的步骤如何?我需要这种关系,但只返回一条记录,并且能够立即加载它,因为我正在将它传递给vue.js

public function current_step()
{
    return $this->belongsToMany(MovementStep::class, 'movement_movement_steps')
        ->withPivot('order', 'finished')
        ->where('finished', true)
        ->orderBy('pivot_order', 'desc');
}
请注意,我想在没有额外套餐的情况下这样做

可供选择的解决方案,但带有额外的包:(不是标记为正确的答案,来自@cbaconier的答案)

Laravel有一种类似于数据库中列的方法。这些可以完美地解决您的问题,您可以将它们附加到序列化中

因此,您当前的步骤将是访问器(getter)。函数的语法为
getCurrentStepAttribute()
,该函数可在
CurrentStep
属性上访问。为了避免N+1,当您使用
with('steps')
方法检索模型时,请立即加载步骤。这比将其作为查询运行要好,因为它将始终执行N次

public function getCurrentStepAttribute() {
    return $this->steps
        ->where('finished', true)
        ->sortByDesc('pivot_order')
        ->first();
}
现在,您可以在Movement.php类上使用append属性来包含您的雄辩的访问器

protected $appends = ['current_step'];

与@mrhn提供的答案不同的方法是创建自定义关系。斯派蒂公司的布伦特对此做了调查

虽然我的答案与提供的答案完全相同,但它使我意识到,要么使用软件包,要么使用此答案,要么使用@mrhn答案,您可以避免n+1查询,但最终可能会使用大量水合模型

在这种情况下,我认为不可能避免一种或另一种方法。缓存可能是一个答案

由于我不能完全确定您的模式,因此我将使用我的示例中的users photos示例提供我的解决方案

User.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{

    public function photos()
    {
        return $this->belongsToMany(Photo::class);
    }

    public function latestPhoto()
    {
        return new \App\Relations\LatestPhotoRelation($this);
    }
}

与Brent文章的主要区别在于,我们没有使用
集合
而是返回最新的照片
模型

步骤是否正常工作?@Albertosinaglia Yes和current_step what is returning?@AlbertoSinigaglia它返回所有完成的步骤,我希望它返回第一步one@Collin
->first()
无法处理急切的加载,我认为对于子查询,我需要在任何地方复制,但可以工作这是一个解决方案,但不是最好的。我不知道这是否能满足@SpaceDogCS的需要,但这个解决方案的一个问题是;如果一个动作有500步呢?如果有15个移动,它将包含7500+15个模型,而我们只需要15+15个。然后用一个查询执行,但是你会让查询运行N次我想它可以与此解决方案一起工作,如果你在包含上进行过滤?该解决方案的问题是它不适用于急加载,你不能基于关系急加载,我已经尝试过这个答案对我来说是完美的,我意识到它需要像我在
if($photos->isEmpty())上建议和编辑的软件包一样{
返回null而不是
$users
,但是它给出了一个错误,在这种情况下怎么办?因为没有
当前步骤
它返回类名如果在
initRelation()
方法中用
null
替换
Photo::class
会怎么样?