laravel 反向使用hasOneThrough

更新时间:2024-07-13 16:20
从Mechanic对象可以使用carOwner()来访问owner,
同样在Owner定义一个hasOneThrough来访问mechanic

官方的案例:
   在一个汽车维修的应用程序中,每一个 Mechanic 模型都与一个 Car 模型相关联,同时每一个 Car 模型也和一个 Owner 模型相关联。虽然维修师(mechanic)和车主(owner)在数据库中并没有直接的关联,但是维修师可以通过 Car 模型来找到车主。让我们来看看定义这种关联所需要的数据表:
mechanics
    id - integer
    name - string
 
cars
    id - integer
    model - string
    mechanic_id - integer
 
owners
    id - integer
    name - string
    car_id - integer


class Mechanic extends Model
{
    /**
     * Get the car's owner.
     */
    public function carOwner(): HasOneThrough
    {
        return $this->hasOneThrough(Owner::class, Car::class);
    }
}

class Mechanic extends Model
{
    /**
     * Get the car's owner.
     */
    public function carOwner(): HasOneThrough
    {
        return $this->hasOneThrough(
            Owner::class,
            Car::class,
            'mechanic_id', // Foreign key on the cars table...
            'car_id', // Foreign key on the owners table...
            'id', // Local key on the mechanics table...
            'id' // Local key on the cars table...
        );
    }
}


从Owner对象访问Mechanic可以使用hasOneThrough关系,但方式略有不同。

在Owner模型中,我们可以定义一个通过Car到Mechanic的hasOneThrough关系。这是因为Owner通过Car间接关联到Mechanic。代码如下:

 

class Owner extends Model
{
    /**
     * 获取与此车主关联的机械师。
     */
    public function mechanic(): HasOneThrough
    {
        return $this->hasOneThrough(
            Mechanic::class,
            Car::class,
            'id', // Car表上的本地键
            'id', // Mechanic表上的本地键
            'car_id', // Owner表上的外键
            'mechanic_id' // Car表上的外键
        );
    }
}
  1. 从Owner开始,通过car_id外键找到相关的Car。
  2. 然后从Car,通过mechanic_id外键找到相关的Mechanic。

使用这个关系,您可以这样访问与车主关联的机械师:

$owner = Owner::find(1);
$mechanic = $owner->mechanic;

需要注意的是,这个关系假设每个车主只有一辆车,每辆车只有一个机械师。如果一个车主可能有多辆车,或者一辆车可能有多个机械师,那么关系类型可能需要调整为hasManyThrough。

我们可以在Owner模型中定义一个hasOneThrough关系来访问Mechanic,这提供了一种优雅的方式来遍历这些相关的模型。


如何确定'id', // Car表上的本地键 'id', // Mechanic表上的本地键 'car_id', // Owner表上的外键 'mechanic_id' // Car表上的外键这4个字段

  1. hasOneThrough方法的参数顺序是固定的:
hasOneThrough(
    $related,
    $through,
    $firstKey,
    $secondKey,
    $localKey,
    $secondLocalKey
)
  1. 在我们的例子中:

    • $related 是 Mechanic::class
    • $through 是 Car::class
  2. 剩下的四个参数按顺序对应:

    • $firstKey: Car表上的本地键
    • $secondKey: Mechanic表上的本地键
    • $localKey: Owner表上的外键
    • $secondLocalKey: Car表上的外键
  3. 根据给定的表结构:

    • Owner通过car_id关联到Car
    • Car通过mechanic_id关联到Mechanic
    • 每个表都有一个id作为主键
  4. 因此,我们可以确定:

    • Car表的本地键是'id'
    • Mechanic表的本地键是'id'
    • Owner表上关联到Car的外键是'car_id'
    • Car表上关联到Mechanic的外键是'mechanic_id'

这就是为什么我们最终得到了这样的参数顺序:

'id', // Car表上的本地键
'id', // Mechanic表上的本地键
'car_id', // Owner表上的外键
'mechanic_id' // Car表上的外键
其实就是把正向的参数完全反过来.
生成的sql如下:
update
  `shop_goods_skus`
  inner join `shop_order_goods` on `shop_order_goods`.`shop_goods_sku_id` = `shop_goods_skus`.`id`
set
  `stock` = `stock` + 1,
  `shop_goods_skus`.`updated_at` = '2024-07-13 15:31:57'
where
  `shop_order_goods`.`id` = 2