从预先加载的 Laravel 集合中加载特定列

问题描述

考虑书籍作者的关系。每本书属于一位作者和一位作者有许多本书。 Books 表有像(Id、Title、Version 等)这样的字段,而authors 有像(Id、Name、Address 等)这样的字段。注意 DB 列不遵循认的 Laravel 命名约定。

现在;我想从两个表中获取一些字段。更具体的是,我想要标题、版本、姓名和地址字段。 这是所需的输出

    {
        Title: "Oxford Maths",Version: "2.5",author: "John Doe",}

第一次试用:

return Book::with('author')->get()->map(function ($book) {
    return collect($book)->only(
        [
            'Title','Version',"author"
        ]);
});

第一次试验输出

    {
        Title: "Oxford Maths",author: {
            Id: 1,Name: "John Doe",Address: "Tanzania",deleted_at: null
        }
    }

第二次试用:试过了;

return Book::with([
        'author' => function($query){
            $query->select('Name','Id');
        }
    ])->get()->map(function ($data) {
    return collect($data)->only(
        [
            'Title',"author"
        ]);
});

还有这个;

return Book::with('authority:name,Id')->get()->map(function ($data) {
    return collect($data)->only(
        [
            'Title',"author"
        ]);
});

第二次试验输出

    {
        Title: "Oxford Maths",author: {
            Name: "John Doe",Id: 1
        }
    }

第三次审判:

return Book::with([
        'author' => function($query){
            $query->select('Name'); // *Removed foreignKey*
        }
    ])->get()->map(function ($data) {
    return collect($data)->only(
        [
            'Title',"author"
        ]);
});

第三次试验输出

    {
        Title: "Oxford Maths",author: null
    }

我该怎么做才能获得所需的输出

解决方法

当然,您可以事后在集合上执行此操作,但直接在查询上执行此操作更有意义。您尝试在第三次试验中反映这一点。但是,在我看来,这是 Laravel behaves a bit odd。为了进行急切加载,您需要外键。尽管这是合乎逻辑的,但人们还是会忘记这一点。但是如果您忘记包含外键,Laravel 不会告诉您这一点,而是返回 null。因此,请确保所有必要的主键和外键始终包含在您的关系中。

return Book::with([
    'author' => function($query){
        $query->select('id','Name'); // *Removed foreignKey*
    }
])->get([ 'title','version' ]);

有一件事,当一个关系应该主要只返回它的一个值时,我喜欢做:

class Author extends Model
{
    public function __toString()
    {
        return $this->Name;
    }
}

要以这种方式自动序列化,您可以将 __toString() 更改为 jsonSerialize()

class Author extends Model implements JsonSerializable
{
    public function jsonSerialize()
    {
        return $this->Name;
    }
}
,

也许对你有帮助

在模型中

protected $appends = [
    'author_name','address'
];

protected $fillable = [
    'title','version',];

public function author(){
    return $this->belongsTo(Author::class);
}

public function getAuthorNameAttribute(){
    return $this->author->name;
}

public function getAddressAttribute(){
    return $this->author->address;
}

在控制器中使用这个

return Book::query()->with('author')->first()->makeHidden(['author','author_id']);

输出:

{
  "id": 1,"title": "book","version": "v1","created_at": null,"updated_at": null,"author_name": "komeyl","address": "Iran"
}
,

我最终使用了@komeyl-dev 建议的技巧。这是示例代码:

//Book.php
class Book extends Model
{
    protected $appends = ['author_name']; // appended so I can access it as json

    public function author(){
        return $this->belongsTo(Author::class,'author_id');
    }
    
    public function getAuthorNameAttribute(){
        return $this->author->name;
    }
}

//Testing in web.php (Note: No eager loading here)
Route::get('url',function () {
    return Book::get()->map(function ($data) {
        return collect($data)->only(
            [
                'Title','Version',"author_name"
            ]);
    });
});

谢谢@shaedrich 和@komeyl-dev

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...