【问题标题】:Laravel Eloquent getting data (with relationship) confusionLaravel Eloquent 获取数据(有关系)的困惑
【发布时间】:2021-12-15 12:27:33
【问题描述】:

我对如何正确地从 Eloquent 模型中提取数据有点困惑。我确实阅读了文档,但没有在任何地方提及,或者我错过了。

假设我们有两个模型,ClientCountry(注意:我只添加了相关代码,否则这个问题会很长):

客户:

<?php

namespace App\Models\Client;

use App\Models\BaseModel;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

/**
 * @property int    id
 * @property int    country_id
 */
class Client extends BaseModel
{
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        ...
        'country_id',
        ...
    ];

    /**
     * Return Country relationship
     *
     * @return BelongsTo
     */
    public function country(): BelongsTo
    {
        return $this->belongsTo(Country::class);
    }
}

国家:

<?php

namespace App\Models\Country;

use App\Models\BaseModel;
use Illuminate\Database\Eloquent\Relations\HasMany;

/**
 * @property int    id
 */
class Country extends BaseModel
{
    public function clients(): hasMany
    {
        return $this->hasMany(Client::class);
    }
}

没什么特别的,两个普通模型。现在,当我尝试提取数据时,我遇到了一些问题:

  • dd(Country::findOrFail(32)); // 正确:返回所选国家
  • dd(Country::findOrFail(32)-&gt;first()); // 错误:返回数据库中的第一个国家,而不是 ID 为 32 的国家,预期:具有选定国家/地区的单个国家对象
  • dd(Country::findOrFail(32)-&gt;get()); // 错误:返回数据库中的所有国家/地区,预期:包含一个国家/地区的对象数组
  • dd(Country::with('clients')-&gt;findOrFail(32)-&gt;first()); // 错误:返回数据库中的第一个国家,而不是 ID 为 32 的国家,关系也不正确,预期:对象与选定国家的有效关系(客户)作为对象数组
  • dd(Country::findOrFail(32)-&gt;clients()); // 错误:返回 HasMany 关系,无数据,预期:作为对象的客户端数组
  • dd(Country::findOrFail(32)-&gt;clients()-&gt;get()); // 正确:返回有效数据,客户端数组作为对象
  • dd(Country::findOrFail(32)-&gt;clients()-&gt;first()); // 正确:返回所选国家/地区的第一个客户

那么,为什么所有错误的都是错误的?我是否错误地解释了文档?最令人沮丧的是dd(Country::with('clients')-&gt;findOrFail(32)-&gt;first()),因为现在我无法根据选定的国家/地区进行过滤,然后还提供该国家/地区的客户列表。我认为 Eloquent 相当先进,所以我认为我做错了什么,并希望得到一些指导。 请注意,在最新示例中,我还尝试将查询反转为dd(Country::findOrFail(32)-&gt;with('clients')-&gt;first()),结果相同。

【问题讨论】:

    标签: laravel eloquent


    【解决方案1】:

    在我看来,您在这里混淆了一些东西。例如,将 FindOrFail() 与 first() 组合是双倍的。看这里,这是我找到的一个很好的解释:

    1. find($id) 接受一个 id 并返回一个模型。如果没有匹配 模型存在,它返回 null。
    2. findOrFail($id) 接受一个 id 并返回一个模型。如果不存在匹配的模型,则会引发错误1。
    3. first() 返回在数据库中找到的第一条记录。如果不存在匹配的模型,则返回 null。
    4. firstOrFail() 返回在数据库中找到的第一条记录。如果不存在匹配的模型,则会引发错误1。
    5. get() 返回与查询匹配的模型集合。
    6. pluck($column) 返回仅包含给定列中的值的集合。在之前的 Laravel 版本中,这个方法被称为列表。
    7. toArray() 将模型/集合转换为简单的 PHP 数组。

    来源:https://stackoverflow.com/a/33027466/14807111

    【讨论】:

      【解决方案2】:

      Builder方法FindOrFail()的方法描述为:

       * Find a model by its primary key or throw an exception.
      

      在您的用例中,此方法调用find()方法并执行:

      $this->whereKey($id)->first($columns);
      

      这将返回第一个模型,默认情况下返回其所有列。因此之后的任何其他first() 都会引入另一个查询。

      您的前三个“错误”是因为执行顺序,查询首先执行 findOrFail,然后再次对整个查询调用 first()

      第四个“错误”的发生是因为您的关系返回了一个 hasMany 关系,这是正常行为。您可以在之后致电-&gt;get() 或致电-&gt;clients 而不使用() 来接收收藏。

      毕竟你使用first() 方法是错误的。您要么使用find()findOrFail(),要么使用-&gt;first()。但是你不应该一起使用它们(可能有一些你必须使用的极端情况,但从流派上来说,不要!)。 使用 find()findOrFail() 将已经返回与 ID 匹配的 first() 元素。

      【讨论】:

        猜你喜欢
        • 2019-11-19
        • 2018-12-27
        • 1970-01-01
        • 2017-05-01
        • 2020-10-08
        • 2021-12-10
        • 2018-01-11
        • 2013-12-14
        • 2017-01-12
        相关资源
        最近更新 更多