laravel eloquent 'has' 方法的行为异常

laravel eloquent 'has' method behaves in an unexpected way

如果至少有一个 User,我想获取 Section 模型的集合。从文档中 has() 方法可以做到这一点,太棒了。检索到的集合中没有 users 关系。然而,当我遍历集合时,我可以获得 users 的属性。为什么?

class Section extends Model
{
    protected $guarded = [];

    public function users()
    {
        return $this->hasMany('App\User');
    }
}
class User extends Authenticatable
{
    protected $guarded = [];

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

我做的是这样的:

$section = Section::where('id' , 1)->has('users')->get();

合集是这样的:

Illuminate\Database\Eloquent\Collection {#3025
     all: [
       App\Section {#3015
         id: 1,
         class_id: 1,
         section_name: "A",
         created_at: "2019-12-14 18:26:01",
         updated_at: "2019-12-14 18:26:01",
       },
     ],
   }

现在奇怪的是,当我执行以下操作时,即使在集合中不存在 users 关系,它也会提供用户的属性。

为什么?

 @foreach ($section as $section)
   @foreach ($section->users as $student)
     <p>{{$student->name}}</p>
   @endforeach
@endforeach
solomon
uche
kene

好的,我明白你的问题了。

  1. 第一个

has方法并不意味着它将包含User。这意味着 return 所有 sections 至少有一个用户。我认为 is/are 用户 Section id ===1。因此,在您的代码中使用 has 或不使用它都没有任何区别。

如果你想加载一个明确的关系你应该使用with

Section::where('id' , 1)->with('users')->get();。然后你应该在每个部分下都有用户集合。

  1. 第二

    您仍然可以访问 blade 文件中的用户属性的原因是 lazy loading。即使它不包含在原始数据库查询和结果中,但是当您尝试访问它时 laravel 仍然会尝试为您获取它们。这可能会导致 N+1 问题。

看起来像你的第一个回声:

$section = Section::where('id' , 1)->has('users')->get();

只打印它有用户的部分,但你并没有具体说也给我用户。

在下一个循环中,您将遍历视图中的每个部分,特别是循环关系。这可以通过以下行看到:@foreach ($section->users as $student)

我在这里阅读文档:https://laravel.com/docs/6.x/eloquent-relationships#querying-relations

在打印该部分时的第一个回显中,您可以获得这样的用户:echo $section-> users()

这就是 Laravel 的工作原理。

访问 $model->{relationship},在你的例子 $section->users 中,是一个神奇的功能,它检查你是否通过 Section::with('users') 之类的东西明确加载了关系,如果你没有,然后加载它。

您在 运行 dd($section) 时看不到 users 的原因是您没有明确加载关系,但这并不意味着它不可用。如果您在初始查询中包含 with('users'),您会看到以下内容:

$section = Section::where('id' , 1)->has('users')->with('users')->get();

App\Section {#3015
   id: 1,
   class_id: 1,
   section_name: "A",
   created_at: "2019-12-14 18:26:01",
   updated_at: "2019-12-14 18:26:01",
   users: [
     0 => App\User {#3016}
       id: ...
       name: ...
   ]
 },

// Or similar

基本上,您没有加载关系,因此在使用 dd($section) 时看不到它,但由于 Laravel,它在 PHP 中仍然可用]的魔术方法。

我还应该注意,为您的查询使用正确的变量命名和闭包(->get()->first() 等)。

$section 在使用 ->get() 时是一个糟糕的名称,因为您要从数据库中取回多条记录。要么使用 $sections,要么将闭包更改为 ->first(),如果使用 ->first(),则不要使用 foreach()