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
好的,我明白你的问题了。
- 第一个
has
方法并不意味着它将包含User
。这意味着 return 所有 sections
至少有一个用户。我认为 is/are 用户 Section
id ===1。因此,在您的代码中使用 has
或不使用它都没有任何区别。
如果你想加载一个明确的关系你应该使用with
Section::where('id' , 1)->with('users')->get();
。然后你应该在每个部分下都有用户集合。
第二
您仍然可以访问 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()
。
如果至少有一个 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
好的,我明白你的问题了。
- 第一个
has
方法并不意味着它将包含User
。这意味着 return 所有 sections
至少有一个用户。我认为 is/are 用户 Section
id ===1。因此,在您的代码中使用 has
或不使用它都没有任何区别。
如果你想加载一个明确的关系你应该使用with
Section::where('id' , 1)->with('users')->get();
。然后你应该在每个部分下都有用户集合。
第二
您仍然可以访问
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()
。