Laravel 急切加载 - 仅加载特定列

47

我正在尝试在Laravel中进行贪婪加载模型,但只返回特定的列。我不想呈现整个贪婪加载的表格。

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

我遇到了以下错误:

log.ERROR:异常'Symfony\Component\Debug\Exception\FatalErrorException',消息为“调用未定义的方法Illuminate\Database\Eloquent\Collection::getAndResetWheres()”


->get(['col','col2','col3']); - mercury
11个回答

77

利用 select() 方法:

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

注意:记得添加分配给外键的列以匹配两个表。例如,在我的示例中,我假设一个所有者拥有一辆汽车,这意味着分配给外键的列应该像owners.id = cars.owner_id这样,所以我必须将owner_id添加到所选列的列表中;


4
很遗憾,这对我不起作用。如果我添加select()方法,则关系不会被添加。如果我删除它,我将获得整行数据。 - ipengineer
12
噢,你可能需要使用外键。例如,如果是id,你需要将id添加到select()中选择的列中。 - rmobis
2
我刚刚更新了原始答案,请现在检查一下。基本上,如果在 owners.id -> cars.owner_id 上设置了 Owner -> Car 关系,则必须将 owner_id 添加到 select() 的列列表中。 - rmobis
2
花了好几个小时才意识到还需要选择ID,但现在看来这是非常有道理的。谢谢,我点赞了! - jah
我找到了,它是模型上的隐藏属性。 - StealthTrails
显示剩余3条评论

28

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

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

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


1
我想补充一下,如果您想要预加载符合特定约束条件的列的行,则 $q->where() 也适用。 - WhyAyala
1
你还可以添加嵌套关系,例如 Owner::with(['car' =>... , 'car.drivers' => ...]),它们将被正确加载和结构化! - ecdani

21

在您的控制器中,您应该做类似这样的事情

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


11

你可以做的最简单的事情是按照文档进行操作,并按照以下方式获取特定列,无需任何额外的代码或闭包。请按照以下步骤进行操作:

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

当你使用 eager load 时,只选择想要的列

$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

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


2
这正是我一直在寻找的!Laravel文档中没有提到这种语法,而我只是在调试我的eager加载时发现了它。id注释是我唯一缺少的东西。如果缺少它,你认为他们会注入它,或者至少记录它的存在。谢谢!(更正:它已经被记录了,但不在我卡在的版本5.3中。也感谢@Bogdan提供的额外说明。) - cautionbug
1
起初我认为在使用eager加载时总是带上id列即使我们不需要它,这是一个bug。但后来我意识到这是必要的,以防止SQL出现“歧义”id错误,因为在连接操作中SQL无法理解你所指的是哪个id列。@cautionbug - Shahrukh Anwar
1
在您的评论中,您提到逗号(,)后面不应该有空格。这个见解帮助我理解了我的错误。谢谢您。 - Irfan Ullah
很高兴它起作用了。 - undefined

5

shahrukh-anwarBogdan 的回答都非常好,帮我解决了这个问题。

不过,我想补充一个关键点以便更好地理解(即使文档中也没有提到)。

以下代码片段在我的情况下仍然无法工作:

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

在主模型(->get(...))中很少看到具体的列选择,因此很容易忘记:您需要外键列来进行选择:

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

当你使用闭包和这种语法时,一旦形成心理联系,似乎很明显,但仍然很容易忽略。

当你有30多列的表格,但只需要其中的3列时,这可能会减轻你的内存负担。


1
在急切加载中,还可以指定要加载的特定列。假设您有这个模型类。
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">此处。


1

使用load更加容易。 如果我们已经实例化了一个模型,例如有一个具有一对多关系的模型User和模型Comments,并且我们只想从Comment中选择id和title

在User模型中,关系方法是

public function comments()
    {
        return $this->hasMany(Comment::class);
    }

在评论模型中,关系方法是:
public function user()
    {
        return $this->belongsTo(User::class);
    }

在我们的控制器中,如果我们想要恢复用户及其评论。
$user = new User();

$user->load('comment:id,title')

我们将仅加载具有id和title的评论关系的用户 :-)


0

对于嵌套关系,我们可以使用这个

 Post::with(['user' => function ($query) {
            $query->select('id','company_id', 'username');
        }, 'user.company' => function ($query) {
            $query->select('id', 'name');
        }])->get();

您的答案可以通过添加更多支持信息来改进。请[编辑]以添加进一步细节,例如引用或文档,以便其他人可以确认您的答案是否正确。您可以在帮助中心中找到有关如何撰写良好答案的更多信息。 - Community

0
尝试使用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();

0

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

Voucher::with(['storeInfo:id,name as branchName,code as branchCode'])->get();

在模型中

public function storeInfo() { return $this->belongsTo(Branch::class,'branch_id'); }


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接