laravel eloquent 'has' 方法的行为出人意料
Posted
技术标签:
【中文标题】laravel eloquent \'has\' 方法的行为出人意料【英文标题】:laravel eloquent 'has' method behaves in an unexpected waylaravel eloquent 'has' 方法的行为出人意料 【发布时间】:2020-04-09 08:44:39 【问题描述】:如果 Section 模型至少有一个 User
,我想获取它的集合。从文档中,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
。这意味着将返回所有至少有一个用户的sections
。我认为有Section
id ===1 的用户。因此,无论在您的代码中是否使用has
,都没有任何区别。
如果你想显式加载关系,你应该使用with
Section::where('id' , 1)->with('users')->get();
。那么你应该在每个部分下都有用户集合。
第二
您仍然可以访问blade
文件中的用户属性的原因是lazy loading
。即使它不包含在原始数据库查询和结果中,但是当您尝试访问它时,laravel 仍然会尝试为您获取它们。这可能会导致 N+1 问题。
【讨论】:
如果您查看该集合,您会注意到没有“用户”关系,我要说的是循环不应该将“用户”的属性作为“集合中不存在用户的关系。但确实如此,这就是为什么我很困惑,我想知道为什么会这样。 这大部分是正确的,但是您仍然可以(并且通常应该)将has()
与with()
结合使用; has()
将处理 Section
、with()
的基于计数的过滤,并急切加载关系以避免您提到的 N+1
问题。在上面的代码中,你仍然可以得到没有任何User
s 的Section
模型,这似乎违背了原问题的意图。
@TimLewis 我认为他对has
方法感到困惑,他认为has
意味着包含关系,事实并非如此。【参考方案2】:
看起来像你的第一个回声:
$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 环境。 你是对的,现在刚刚浏览了文档,现在对我来说更清楚了..【参考方案3】:这就是 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()
。
【讨论】:
以上是关于laravel eloquent 'has' 方法的行为出人意料的主要内容,如果未能解决你的问题,请参考以下文章
Laravel Eloquent:通过具有多个关系的枢轴将表绑定到另一个表
在 Laravel Eloquent 中获取 HasOne 关系中的特定列
php [Eloquent CheatSheet] Eloquent #laravel #eloquent的常见查询方法