雄辩地从多个联接中检索数据

时间:2020-04-30 10:55:55

标签: php sql laravel 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)

我希望在我的trips()模型上有一个Delivery方法,该方法返回该结果。 但是,我对于如何使用Eloquent实现这一目标感到困惑。

2 个答案:

答案 0 :(得分:1)

不幸的是,我们可以简单地使用union方法来实现此目的,但似乎不适用于hasManyThrough关系。

无论如何,我认为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();

答案 1 :(得分:0)

如果您想使用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
        );
    }
}