首页 > 解决方案 > 模型追加,包括查询中的整个关系

问题描述

编辑:我能够看到我的回复中包含的关系,但我仍然不知道为什么。

在我的Customer模型上,我有:

protected $appends = [
        'nps',
        'left_feedback',
        'full_name',
        'url'
    ];

访问器如下:

/**
     * Accessor
     */
    public function getNpsAttribute() {
        if ($this->reviews->count() > 0) {
            return $this->reviews->first()->nps;
        } else {
            return "n/a";
        }
    }



    /**
     * Accessor
     */
    public function getLeftFeedbackAttribute() {
        if ($this->reviews && $this->reviews->count() > 0 && $this->reviews->first()->feedback != null) {
            return "Yes";
        } else {
            return "No";
        }
    }

    /**
     * Accessor
     */
    public function getFullNameAttribute() {
       return ucwords($this->first_name . ' ' . $this->last_name);
    }


    /**
     * Accessor
     */
    public function getUrlAttribute() {
        $location = $this->location;
        $company = $location->company;
        $account_id = $company->account->id;

        return route('customers.show', ['account_id' => $account_id, 'company' => $company, 'location' => $location, 'customer' => $this]);
       
     }

因此,如果我注释掉该$appends属性,我会得到我最初想要的响应,而客户不会在我的响应中返回所有关系。

但我确实想要我的客户对象上的那些附加字段。我不明白为什么它会包括它在响应中使用的所有关系。我正在返回特定的字符串。

那么有没有办法让我的$appends而不是它在访问器中使用的所有关系都被包含在内?


原始问题:

我正在查询属于客户的评论。我想将客户关系作为评论的一部分,但我不想包括客户关系。

$reviews = $reviews->with(['customer' => function($query) {
            $query->setEagerLoads([]);
            $query->select('id', 'location_id', 'first_name', 'last_name');
        }]);

$query->setEagerLoads([]);在这种情况下不起作用。

我也试过$query->without('location');了,但它仍然包含在内

我应该注意我没有$with在模型上填充任何属性。

这是Review模型关系:

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

这是Customer模型关系:

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


    // I dont want these to be included
    public function location() {
        return $this->belongsTo('App\Location');
    }

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

在响应中,它看起来像:

'review' => [
 'id'=> '1'
 'customer => [
   'somecol' => 'test',
   'somecolagain' => 'test',
   'relation' => [
      'relation' => [

      ]
   ],
   'relation' => [
       'somecol' => 'sdffdssdf'
    ]
  ]
]

因此,一系列关系最终被加载,我不想要它们。

标签: laraveleloquent

解决方案


正如您在对主要问题的一条评论中所说,由于附加的访问器,您得到了关系。

让我向您展示应该如何完成(我将复制粘贴您的代码并简单地编辑一些部分,但您仍然可以复制粘贴我的代码并将其放入您的代码中,并且将以相同的方式工作,但会阻止添加关系)和然后让我解释一下为什么会这样:

/**
 * Accessor
 */
public function getNpsAttribute() {
    if ($this->reviews()->count() > 0) {
        return $this->reviews()->first()->nps;
    } else {
        return "n/a";
    }
}



/**
 * Accessor
 */
public function getLeftFeedbackAttribute() {
    return $this->reviews()->count() > 0 && 
           $this->reviews()->first()->feedback != null 
        ? "Yes" 
        : "No";
}

/**
 * Accessor
 */
public function getFullNameAttribute() {
   return ucwords($this->first_name . ' ' . $this->last_name);
}


/**
 * Accessor
 */
public function getUrlAttribute() {
    $location = $this->location()->first();
    $company = $location->company;
    $account_id = $company->account->id;

    return route('customers.show', ['account_id' => $account_id, 'company' => $company, 'location' => $location, 'customer' => $this]);
   
 }

如您所见,我已将 any 更改$this->relation$this->relation()->first()or $this->relation->get()

如果您访问任何模型的关系,因为$this->relation它会将其添加到预先加载(已加载)中,因此它会真正获取关系数据并将其存储在模型的数据中,因此下次您$this->relation再次访问时,它不必去数据库和查询再次。

因此,为防止这种情况,您必须访问关系 as $this->relation(),这将返回一个查询构建器,然后您可以执行->count()or->exists()->get()or->first()或任何其他有效的查询构建器方法,但是作为查询构建器访问关系将阻止获取数据和将它存储在模型中(我知道正在做->get()->first()将要获取数据,但您不是直接通过模型获取它,而是通过查询构建器关系获取它,这是不同的)。

这样,您将防止将数据存储在模型上,从而给您带来问题。

您也可以使用API Resources,它用于将模型或集合映射到所需的输出。

最后一件事,如果你可以使用它$this->relation()->exists()来代替它,这$this->relation()->count() > 0将有助于更快地完成它,大多数情况下,任何数据库在查看数据是否存在(count >= 1exists


推荐阅读