【问题标题】:Laravel Eager Loading - Load only specific columnsLaravel Eager Loading - 仅加载特定列
【发布时间】:2013-06-04 08:38:18
【问题描述】:

我试图在 laravel 中急切地加载模型,但只返回某些列。我不希望呈现整个急切加载的表格。

public function car()
{
    return $this->hasOne('Car', 'id')->get(['emailid','name']);
}

我收到以下错误:

log.ERROR: 异常 'Symfony\Component\Debug\Exception\FatalErrorException' 带有消息 'Call to undefined method Illuminate\Database\Eloquent\Collection::getAndResetWheres()'

【问题讨论】:

  • ->get(['col','col2','col3']);

标签: php laravel laravel-4


【解决方案1】:

利用select()方法:

public function car() {
    return $this->hasOne('Car', 'id')->select(['owner_id', 'emailid', 'name']);
}

注意:记得添加分配给匹配两个表的外键的列。例如,在我的示例中,我假设Owner 具有Car,这意味着分配给外键的列将类似于owners.id = cars.owner_id,因此我必须将owner_id 添加到选定列的列表中;

【讨论】:

  • 不幸的是,这对我不起作用。如果我添加 select() 方法,则不会添加关系。如果我删除它,我会得到整行。
  • 哦,您可能还需要使用外键。例如,如果它是id,则需要将id 添加到select()'ed 列中。
  • 我刚刚更新了原始答案,现在检查一下。基本上,如果在owners.id -> cars.owner_id 上设置了Owner -> Car 关系,则必须将owner_id 添加到select() 的列列表中。
  • 在这上面花了几个小时,从没想过还要选择 id。但现在它非常有意义。谢谢,我赞成!
  • 如果我想从结果中隐藏外键怎么办?
【解决方案2】:

此外,您无需指定获取模型中的特定列和关系方法本身...您可以在需要时执行此操作...就像这样:

$owners = Owner::
          with([
              'car' => function($q)
               {
                    $q->select('id', 'owner_id', 'emailid', 'name');
               },
               'bike' => function($q)
               {
                    $q->select('id', 'owner_id', 'emailid', 'name');
               }
          ])->
          get();

通过这种方式,您还可以获得相关模型的所有列,如果您曾经需要的话。

【讨论】:

  • 我想补充一点,如果您想急切地加载具有匹配某些约束的列的行,这也适用于 $q->where()
  • 您还可以添加嵌套关系,如Owner::with(['car' =>... , 'car.drivers' => ...]),它们将被正确加载和结构化!
【解决方案3】:

在您的控制器中,您应该执行类似

的操作
App\Car::with('owner:id,name,email')->get();

假设您定义了两个模型,如下所示

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;

class Car extends Model
{
    protected $table = 'car';

    public function owner()
    {
        return $this->belongsTo('App\Owner', 'owner_id');
    }
}

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;

class Owner extends Model
{
    protected $table = 'owner';

    public function car()
    {
        return $this->hasMany('App\Car', 'owner_id');
    }
}

你有两个类似的表:

owners: id | name | email | phone | other_columns...

cars: id | owner_id | make | color | other_columns...

感谢文档:eloquent-relationships#eager-loading 滚动到 Eager Loading Specific Columns

【讨论】:

    【解决方案4】:

    您可以做的最简单的事情是阅读文档并执行以下操作以仅获取特定列,而无需任何额外的代码行或闭包。按照步骤,

    public function car(){
        return $this->hasOne('Car', 'id');
    }
    

    然后当您急切加载关系时,仅选择选定的列

    $owner = $this->owner
    ->where('id', 23)
    ->with('car:id,owner_id,emailid,name')   //no space after comma(, ) and id has to be selected otherwise it will give null
    

    希望这有效,祝你有美好的一天。

    【讨论】:

    • 这就是我一直在寻找的! Laravel 文档没有给出这种语法的提示,我只是在调试为什么我的渴望不会加载时才发现它。 id 注释是我唯一缺少的东西。你认为如果它丢失,他们会注入它,或者至少记录它的存在。谢谢! (更正:它已记录在案,但不在我坚持的版本中 - 5.3。还要感谢@Bogdan 的附加说明。)
    • 最初我认为即使我们不想要id 列,也总是在急切中使用id 是一个错误。但后来我意识到防止SQL的ambiguous id 错误是相当必要的,因为SQL 不明白你在joins 期间谈论的是哪个id 列。 @cautionbug
    【解决方案5】:

    shahrukh-anwarBogdan 的答案都很出色,让我解决了这个问题。

    但是,我要添加一个关键部分以进行澄清(甚至文档都没有提及)。

    采取以下,对我来说仍然是坏的:

    Car::with('owner:id,name,email')->get(['year', 'vin']); 
    

    您很少在主模型 (-&gt;get(...)) 上看到特定的列选择,因此很容易忘记:您的选择需要外键列:

    Car::with('owner:id,name,email')->get(['owner_id', 'year', 'vin']);
    

    当然,一旦你在使用闭包和这种语法之间建立了心理联系,这似乎很明显,但仍然很容易被忽视。

    当您的表包含 30 多列并且只需要其中 3 列时,这可能会降低您的内存负载。

    【讨论】:

      【解决方案6】:

      尝试 WITH()WHERE() 条件。

      $user_id = 1; // for example
      
      Post::with(array('user'=>function($query) use ($user_id ){
                  $query->where('user_id','=',$user_id );
                  $query->select('user_id','username');
              }))->get();
      

      【讨论】:

        【解决方案7】:

        有时您需要使您的关系通用化,以便您轻松自如。

        public function car()
        {
            return $this->hasOne('Car', 'id');
        }
        

        在获取时您可以提及您需要的列。

        $owners = Owner::with(['car' => function($query) { // eager loading
                    $query->select('emailid','name');
                   }
                  ])->get();
        
        foreach($owners as $owner){
            $owner->car->emailid;
            $owner->car->name;
        }
        

        【讨论】:

          【解决方案8】:

          也可以在预先加载时指定要加载的特定列。 假设你有这个模态类

          class user extends Model {
            public function car()
              {
                return $this->hasOne('Car', 'id')->get(['emailid','name']);
              }
          }
          

          如果您想为用户加载汽车,您可以在控制器上执行此操作

          User::with(['car:id,emailid,name'])->get(); 
          

          :-注意 不要忘记在你想要获取的列中添加外键,否则它现在可以工作了。你需要一个汽车模型以及反向关系。

          更多细节可以参考这个

          Eager Loading Specific Columns

          【讨论】:

            【解决方案9】:

            确保在使用急切加载时放置 id 列

            Voucher::with(['storeInfo:id,name as branchName,code as 分支代码'])->get();

            在模型中

            公共函数 storeInfo() { 返回 $this->belongsTo(Branch::class,'branch_id'); }

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2021-10-17
              • 1970-01-01
              • 2017-05-23
              • 1970-01-01
              • 2017-08-19
              • 1970-01-01
              • 2014-05-10
              • 2020-05-23
              相关资源
              最近更新 更多