在Laravel中,你可以基于不是键的字段建立模型之间的关系吗

pb3s4cty  于 2023-05-23  发布在  其他
关注(0)|答案(1)|浏览(109)

我有三个模型:VehicleLiveDataPlace
在我的Vehicle模型中,我目前在VehicleLiveData之间存在一个关系,它可以获取车辆的最新LiveData

public function latestPosition(): HasOne
{
    return $this->hasOne(LiveData::class)->latestOfMany();
}

现在在我的LiveData模型中,我想在LiveDataPlace之间建立一个关系,但是两者之间没有直接的键,关系是在一个纬度和经度范围之间。这就是在纯SQL中调用关系的方式:

LEFT JOIN `places`
    ON `live_data`.`speed` = 0 AND `places`.`lat` BETWEEN (`live_data`.`lat` - 0.00007) AND (`live_data`.`lat` + 0.00007) AND `places`.`lng` BETWEEN (`live_data`.`lng` - 0.00007) AND (`live_data`.`lng` + 0.00007)

因为我想能够用这种关系来和雄辩像这样:

$vehicles = Vehicle::where('disabled', 0)
    ->with(['latestPosition.place', 'tags'])
    ->get();

这有可能吗?

ilmyapht

ilmyapht1#

是也不是

,可以与非键的字段建立良好的关系。

例如,对于这样的表

+-------+   +----------+
| users |   | profiles |
+-------+   +----------+
| id    |   | ...      |
| email |   | email    |
| ...   |   | ...      |
+-------+   +----------+

您可以使用email而不是key来定义hasOnebelongsTo。外键不是必需的。它们只是使保持数据完整性变得更容易,并且你的rdbms知道如何为它们优化查询。

function profile() { return $this->hasOne(Profile::class, 'email', 'email');

,您不能定义在后台执行该精确查询的关系。除非你要实现一个自定义的Relation类。Laravel没有提供(据我所知)任何解析为LEFT JOIN子句的关系,该子句将列与值或聚合值进行比较。

您可以定义一个查询范围,封装LiveData模型上的所有逻辑,然后调用它。
我使用$join->where而不是$join->on,因为on被保留用于比较列,而where可以用于比较值。

// LiveData
public function scopeWithPlace(Builder $query)
{
    return $query->leftJoin('places', function (JoinClause $join) {
        $join->where('live_data.speed', 0)
            ->whereRaw('places.lat BETWEEN (live_data.lat - ?) AND (live_data.lat + ?)', [0.00007, 0.00007])
            ->whereRaw('places.lng BETWEEN (live_data.lng - ?) AND (live_data.lng + ?)', [0.00007, 0.00007])
    })
    ->addSelect('places.*');
}
$vehicles = Vehicle::query()
    ->where('disabled', 0)
    ->with([
        'latestPosition' => fn ($liveData) => $liveData->withPlace(),
        'tags'
    ])
    ->get();

相关问题