Laravel Eloquent最大限度地提高效率,但保持优雅的结构


Laravel Eloquent maximize efficiency but keep elegant structure

我在应用程序的一个敏感部分工作,我需要确保尽量减少查询的数量。我可以通过多次连接轻松完成此操作。问题是:有没有一种方法可以用美来做到这一点?

间接关系是一个很好的起点,但大多数时候它需要多个查询。

本文中使用的热切加载方法看起来要好得多,但仍然需要至少2个查询,并且使用whereIn语句而不是联接。

文章热切装载的例子:

$users = User::with('posts')->get();
foreach($users as $user)
{
  echo $user->posts->title;
}

使用Eager Loading,Laravel实际上会运行以下

select * from users
select * from posts where user_id in (1, 2, 3, 4, 5, ...) 

我目前的解决方案是以一种无意的方式使用laravel作用域。

    public static function scopeUser($query) // join users table and user_ranks
    {
        return $query->join('users', 'users.id', '=', 'posts.user_id')
                     ->join('user_ranks', 'users.rank_id', '=', 'user_ranks.id');
    }
    public static function scopeGroup($query,$group_id) // join feeds,group_feeds (pivot) and groups tables
    {
        return $query->join('feeds', 'feeds.id', '=', 'posts.feed_id')
                     ->join('group_feed', 'feeds.id', '=', 'group_feed.feed_id')
                     ->join('groups', 'groups.id', '=', 'group_feed.group_id')
                     ->where("groups.id","=",$group_id);
    }

结果查询如下:

$posts = Post::take($limit)
                ->skip($offset)
                ->user()                   // scropeUser
                ->group($widget->group_id) // scropeGroup
                ->whereRaw('user_ranks.view_limit > users.widget_load_total')
                ->groupBy('users.id')
                ->orderBy('posts.widget_loads', 'ASC')
                ->select(
                             'posts.id AS p_id',
                             'posts.title AS p_title',
                             'posts.slug AS p_slug',
                             'posts.link AS p_link',
                             'posts.created_on AS p_create_on',
                             'posts.description AS p_description',
                             'posts.content AS p_content',
                             'users.id AS u_id',
                             'users.last_name AS u_last_name',
                             'users.first_name AS u_first_name',
                             'users.image AS u_image',
                             'users.slug AS u_slug',
                             'users.rank_id AS u_rank',
                             'user_ranks.name AS u_rank_name',
                             'user_ranks.view_limit AS u_view_limit'
                         )
                ->get();

由于列名冲突,我需要一个巨大的select语句。这可以工作并生成一个查询,但它一点也不性感!

有没有更好的方法来处理大型联接查询?

您可以尝试在作用域中实际添加带有别名的select。

注意:这完全未经测试

public static function scopeUser($query) // join users table and user_ranks
{
    foreach(Schema::getColumnListing('users') as $column){
        $query->addSelect('users.'.$related_column.' AS u_'.$column);
    }
    $query->addSelect('user_ranks.name AS u_rank_name')
          ->addSelect('user_ranks.view_limit AS u_view_limit');
    $query->join('users', 'users.id', '=', 'posts.user_id')
          ->join('user_ranks', 'users.rank_id', '=', 'user_ranks.id');
    return $query;
}

也不需要使用p_前缀对post列进行别名。。。但是,如果您真的想这样做,请添加另一个这样做的作用域,并使用addSelect()