关于laravel使用扩展l5-repository时避免过度查询

前言:l5-repository应用于抽象数据层,使我们的应用程序更易于维护。今天我们通过一个例子来说明如何使用l5-repository动态地查询关联数据,避免过度查询

一、laravel代码层面--一个完整的l5-repository使用流程和解决方案

描述:以目标清单列表all接口请求过慢为例子(直接获取所有的目标清单,目标清单数据在1800条左右,数据很少,但是请求需要30秒左右,原因在于Transformer层(转化者)里默认关联获取user信息,user表有近千万条的数据,慢的原因在于查询此表,但是在现有的业务逻辑是不需要此参数的,属于过度查询)

1.model层(数据操作者)

<?php
namespace App\Repositories;

use Illuminate\Database\Eloquent\Model;

// 目标清单列表模型
class TargetList extends BaseModel
{
    public function user()
    {
        return $this->belongsTo(\Wunsun\Cms\Auth\Models\User::class, 'user_id');
    }
}

2.repository层(仓库管理者,作为model的辅助者)

<?php
namespace App\Repositories;

use Prettus\Repository\Eloquent\BaseRepository
use App\Models\TargetList;
use App\Presenters\TargetListPresenter;

class TargetListRepository extends BaseRepository
{
    public function model()
    {
        return TargetList::class;
    }

    public function presenter()
    {
        return TargetListPresenter::class;
    }
}

3.Presenter层(演示者,也就是数据演示)


namespace App\Presenters;


use App\Transformers\TargetListTransformer;

class TargetListPresenter extends BasePresenter
{
    public function getTransformer()
    {
        return new TargetListTransformer();
    }
}

4.Transformer层(转化者,辅助演示者进行数据转化)

(1)初始的粗糙的关联查询User信息用法(会默认每次进行关联查询)

<?php

namespace App\Transformers;

use App\Transformers\UserTransformer;
use League\Fractal\TransformerAbstract;
use App\Models\TargetList;

class TargetListTransformer extends TransformerAbstract
{
    public function transform(TargetList $model)
    {
        return [
            'id'           => (int)$model->id,
            'name'         => (string)$model->name,
            'status'       => (boolean)$model->status,
            'user'         => $model->user,
            'created_at'   => (string)$model->created_at
        ];
    }

    public function includeUser(TargetList $model)
    {
        $user = $model->user;

        return $this->item($user, new UserTransformer);
    } 
}

(2) 支持动态引入关联User信息(使用availableIncludes参数)

<?php

namespace App\Transformers;

use App\Transformers\UserTransformer;
use League\Fractal\TransformerAbstract;
use App\Models\TargetList;

class TargetListTransformer extends TransformerAbstract
{
    protected $availableIncludes = [
        'user',
    ];

    public function transform(TargetList $model)
    {
        return [
            'id'           => (int)$model->id,
            'name'         => (string)$model->name,
            'status'       => (boolean)$model->status,
            'created_at'   => (string)$model->created_at
        ];
    }

    public function includeUser(TargetList $model)
    {
        $user = $model->user;

        return $this->item($user, new UserTransformer);
    } 
}

5.目标清单列表all接口逻辑代码

(1)使用availableIncludes参数

    /**
     * 获取所有目标清单列表
     *
     * @Get("/all")
     *
     * @return \Illuminate\Http\Response
     */
    public function all(Request $request)
    {
        return $this->response->array($this->repository->pushCriteria(
            new TargetListCriteria(
                $request->user()->id,
                $request->input('city_id', 0)
            ))->all());
    }

6.解决描述

(1)在Transformer转化层内使用availableIncludes参数设置关联User,且此字段是属于动态获取。all接口是不需要使用user信息的。

那么,如何动态获取呢。在接口路由添加参数include(在获取大量数据且关联表数据极大的情况下不推荐)

http://xxx/xx/all?include=user

(2)或者直接再创建一个新的演示者(Presenter)和对应的转化者(Transformer),


    public function all(Request $request)
    {
        return $this->response->array($this->repository->pushCriteria(
            new TargetListCriteria(
                $request->user()->id,
                $request->input('city_id', 0)
            ))->setPresenter(TargetListSimplifyPresenter::class)->all());
    }

    class TargetListSimplifyPresenter extends BasePresenter
    {    
      public function getTransformer()
      {
          return new TargetListSimplifyTransformer();
      }
    }

    class TargetListSimplifyTransformer extends TransformerAbstract
    {
      public function transform(TargetList $model)
      {
          return [
              'id'   => (int)$model->id,
              'name' => (string)$model->name,
          ];
      }
    }

二、总结

  • 在需要获取大量数据的接口中,根据业务的需求查询时应该建立比较有效的索引,避免全表搜索。
  • 避免获取大量数据的接口,还进行关联查询,特别是关联的表是大数据表
  • 根据业务,只返回业务所需字段,避免做全字段查询
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值