【问题标题】:Laravel Eloquent: filtering model by relation tableLaravel Eloquent:按关系表过滤模型
【发布时间】:2015-05-15 14:21:36
【问题描述】:

我有placeslocations 表。 地方可能有很多位置。位置属于地方。

地点: id title

地点: id place_id floor lat lon

class Location extends Model {

    public function place()
    {
        return $this->belongsTo('App\Place');
    }

}

class Place extends Model {

    public function locations()
    {
        return $this->hasMany('App\Location');
    }

}

我需要找到只属于一楼的地方。 select * from places inner join locations on places.id = locations.place_id where locations.floor = 1

在 Eloquent 中应该怎么做?

类似于 Place::where('locations.floor', '=', 1)->get() 存在吗?

是的,我知道有whereHas

Place::whereHas('locations', function($q)
{
    $q->where('floor', '=', 1);
})->get()

但它会生成一个有点复杂的计数查询:

select * from `places` where (select count(*) from `locations` where `locations`.`place_id` = `places`.`id` and `floor` = '1') >= 1

【问题讨论】:

  • 通过whereHas生成的查询有什么问题?
  • 问题在于它是带有聚合计数()函数的奇怪查询。也许,只是也许,引擎 mysql 后面的那个把它翻译成简单的加入(或者加入这个,我真的不知道)。是否等于我提供的加入方法?
  • 问题是,在 Laravel 中,只有在需要时才会发生连接。它在每个步骤中执行最有效的请求。在这种情况下,由于不需要连接,因此不会执行连接,而是使用count()。如果您只是为了提高效率而这样做,那么您要么过度优化,要么不应该使用 Eloquent,因为它速度极慢且占用大量资源。

标签: php laravel eloquent laravel-5


【解决方案1】:

这不行吗?

class Location extends Model {

    public function place()
    {
        return $this->belongsTo('App\Place');
    }

}

$locations = Location::where('floor', '=', 1);
$locations->load('place'); //lazy eager loading to reduce queries number
$locations->each(function($location){ 
    $place = $location->place
    //this will run for each found location 
});    

最后,任何orm都不是为了优化数据库使用,也不值得期待它产生好的sql。

【讨论】:

  • 1 个位置 -> 1 个位置。所以这段代码只为我提供了一个地方,而不是全部来自一楼。
  • 循环访问 $locations,我使用 first() 只是为了演示目的。 ` $locations->each(function($location){ $place = $location->place });`
  • 是的,我知道我可以循环,但这个简单的操作有点复杂。但谢谢你的回答,我想我会用你的方法......我的让我很困惑=(
【解决方案2】:

我没试过这个,但是你有急切的加载,你可以有一个条件:

$places = Place::with(['locations' => function($query)
{
    $query->where('floor', '=', 1);

}])->get();

Source

【讨论】:

  • 很遗憾,它不起作用,这段代码意味着你抓取所有地方,但只为那些在一楼的地方加载关系。
【解决方案3】:

试试这个:

Place::join('locations', 'places.id', '=', 'locations.place_id')
->where('locations.floor', 1)
->select('places.*')
->get();

【讨论】:

    猜你喜欢
    • 2016-10-15
    • 2014-01-15
    • 2018-10-20
    • 2016-02-26
    • 2015-04-04
    • 2021-10-01
    • 2021-07-04
    • 1970-01-01
    • 2014-01-22
    相关资源
    最近更新 更多