【问题标题】:Retrieve data from multiple joins using eloquent使用 eloquent 从多个连接中检索数据
【发布时间】:2020-04-30 10:55:55
【问题描述】:

我正在开发一个项目来跟踪货物的交付。 我的想法是一次送货可以去不同的地方,所有这些地方都通过单程连接。

这是我的 Eloquent 架构:

class Delivery extends Model
{
    public function places()
    {
        return $this->hasMany(Place::CLASS, 'delivery_id');
    }

    public function trips()
    {
        // what should I do here?
    }
}
class Place extends Model
{
    public function delivery()
    {
        return $this->belongsTo(Delivery::CLASS, 'delivery_id');
    }
}
class Trip extends Model
{
    public function departurePlace()
    {
        return $this->belongsTo(Place::CLASS, 'departure_place_id');
    }

    public function arrivalPlace()
    {
        return $this->belongsTo(Place::CLASS, 'arrival_place_id');
    }
}

基本上,我要做的是获取与一次交付相关的所有行程。或者,换一种说法,连接一次送货必须经过的所有地方的所有行程。 这是实现我想要的结果的 SQL 查询:

select distinct trip.*
from delivery
    join place on (place.delivery_id = delivery.id)
    join trip on (place.id = trip.arrival_place_id or place.id = trip.departure_place_id)

我想在我的 Delivery 模型上有一个 trips() 方法,它返回该结果。 但是,我对如何使用 Eloquent 实现这一点感到非常困惑。

【问题讨论】:

  • 从我上面看到的查询来看,送货和旅行之间似乎没有直接联系。如果我正确理解了查询,那将返回曾经在交货地点进行的所有旅行。
  • 是的,完全正确。送货和旅行之间没有联系。需要首先通过场所连接,如 SQL 查询所示。抱歉,我刚刚注意到我的问题中有一个错误。
  • 您的意思是获取所有通过地点的送货行程吗?
  • @Saengdaet 是的,我就是这个意思。

标签: php sql laravel eloquent


【解决方案1】:

不幸的是,我们本可以简单地使用union 方法来实现这一点,但它似乎不适用于hasManyThroughrelations。

无论如何,我认为Eloquent 关系并不意味着用于实现这样的特定查询。

相反,您可以使用Eloquent scopes 来实现此目的。

所以根据@Saengdaet 的回答,我们可以写两个关系,然后将它们与scope 结合起来:

(顺便说一句:我不知道你为什么说他的代码出错了......)

class Delivery extends Model
{
    public function places()
    {
        return $this->hasMany(Place::class);
    }

    public function outboundTrips()
    {
        return $this->hasManyThrough(
            Trip::class, 
            Place::class,
            "delivery_id", // Foreign key on places table
            "departure_place_id", // Foreign key on trips table
        );
    }

    public function inboundTrips()
    {
        return $this->hasManyThrough(
            Trip::class, 
            Place::class,
            "delivery_id", // Foreign key on places table
            "arrival_place_id", // Foreign key on trips table
        );
    }

    public function scopeTrips($query)
    {
        $deliveriesWithTrips = $query->with(['outboundTrips', 'inboundTrips'])->get();

        $trips = [];
        $deliveriesWithTrips->each(function ($elt) use (&$trips) {
            $trips[] = $elt->inboundTrips->merge($elt->outboundTrips);
        });

        return $trips;
    }
}

现在要检索给定交货的所有行程,您只需编写:

 Delivery::where('id', $id)->trips();

【讨论】:

    【解决方案2】:

    如果您想使用Delivery 模型获取所有行程,您可以使用“hasManyThrough”关系,它提供了通过中间关系访问远距离关系的便捷快捷方式。

    但您必须选择您将使用 Trip 模型上的哪个 FK 来关联它

    可以参考"has-many-through" relationship

    class Delivery extends Model
    {
        public function places()
        {
            return $this->hasMany(Place::CLASS, 'delivery_id');
        }
    
        public function trips()
        {
            return $this->hasManyThrough(
                           Trip::Class, 
                           Place::Class,
                           "delivery_id", // Foreign key on places table
                           "departure_place_id", // Foreign key on trips table
                           "id", // Local key on deliveries table
                           "id" // Local key on places table
            );
        }
    }
    

    【讨论】:

    • 您的代码给了我一个错误。我将其更改为 return $this->hasManyThrough(Trip::Class, Place::Class, 'travel_id', 'departure_place_id');> 它可以工作,但显然这并没有返回我想要的所有结果,因为它缺少 arrival_place_id 的额外条件。虽然hasManyThrough 看起来是一个有趣的功能(我不知道),但也许它不是实现我想要的结果的正确方法?
    • 啊我明白了,我只是给你举个例子,因为我实际上并不知道你的 FK 和你的 PK 是什么。
    • 也许你可以在 hasManyThrough 之后添加更多 where 条件来过滤它们
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-17
    • 2018-05-17
    • 1970-01-01
    • 2014-10-11
    • 2020-04-22
    相关资源
    最近更新 更多