Laravel 的 Eloquent ORM 与查询生成器
Laravel's Eloquent ORM versus Query Builder
我有 2 个 table:users
和 articles
。 users
table 有一个名为 is_suspended
的列,它接受 yes
或 no
,而 articles
table 有一个名为 is_published
接受 0
或 1
。要从数据库中获取文章数据,articles.is_published
必须等于 1
并且 users.is_suspended
必须等于 no
。现在假设 users.is_suspended
等于 yes
,如果我尝试像这样使用查询生成器获取文章数据:
// first code:
$articles = Article::join('users', 'articles.user_id', '=', 'users.user_id')
->select(['articles.*', 'users.user_name', 'users.user_email'])
->where('articles.article_id', '=', 9)
->where('articles.is_published', '=', 1)
->where('users.is_suspended', '=', 'no')
->get();
这将完美地工作并且 return 什么都不会(因为 users.is_suspended
= yes
)。现在让我们尝试使用 Laravel Eloquent ORM 获取同一篇文章,如下所示:
// second code:
$articles = Article::with([
'user' => function($query) {
$query->select(['user_id', 'user_name', 'user_email'])
->where('users.is_suspended', '=', 'no');
}])
->where('articles.article_id', '=', 9)
->where('articles.is_published', '=', 1)
->get();
在这种情况下我会得到下一个结果:
[
{
article_id: 9,
user_id: 1,
article_title: "Article title here",
article_body: "Article body here",
is_published: 1,
created_at: "2015-01-17 02:26:24",
updated_at: "2015-01-17 02:26:24",
user: null
}
]
即使用户被挂起,它也会获取文章的数据,这是错误的。所以我的问题是如何修复第二个代码使其像第一个代码一样?
您可能想使用 with
来确保延迟加载关系,但您对其施加的任何约束仅适用于加载的关系。要限制对用户未暂停的文章的响应,您需要使用 whereHas
方法。
$articles = Article::with(['user' => function($q){
$q->select(['user_id', 'user_name', 'user_email', 'created_at']);
}])
->whereHas('user', function($q) {
$q->where('is_suspended', '=', 'no');
})
->where('articles.article_id', '=', 9)
->where('articles.is_published', '=', 1)
->get();
你需要 whereHas
而不是 with
(或两者都需要,但在这种情况下不需要 with
),就像@DavidBarker 说的那样。
但是我建议更多,请考虑这段代码的可读性:
$article = Article::whereHas('user', function ($q) {
$q->active();
})->published()->find(9);
它利用了scopes。
因此,您可以采取以下措施让您的生活更轻松:
将 is_suspended
更改为 bool
因为:
$user->is_suspended; // no
(bool) $user->is_suspended; // true
在 User
模型上定义范围 suspended
并在 Article
上定义范围 published
:
// Article model - on User accordingly
public function scopePublished($query)
{
$query->where('is_published', 1);
}
当你想获取单个模型时使用find($id)
或where('col', $id)->first()
而不是get
,因为后者会return一个集合,甚至虽然只有一个结果。
我有 2 个 table:users
和 articles
。 users
table 有一个名为 is_suspended
的列,它接受 yes
或 no
,而 articles
table 有一个名为 is_published
接受 0
或 1
。要从数据库中获取文章数据,articles.is_published
必须等于 1
并且 users.is_suspended
必须等于 no
。现在假设 users.is_suspended
等于 yes
,如果我尝试像这样使用查询生成器获取文章数据:
// first code:
$articles = Article::join('users', 'articles.user_id', '=', 'users.user_id')
->select(['articles.*', 'users.user_name', 'users.user_email'])
->where('articles.article_id', '=', 9)
->where('articles.is_published', '=', 1)
->where('users.is_suspended', '=', 'no')
->get();
这将完美地工作并且 return 什么都不会(因为 users.is_suspended
= yes
)。现在让我们尝试使用 Laravel Eloquent ORM 获取同一篇文章,如下所示:
// second code:
$articles = Article::with([
'user' => function($query) {
$query->select(['user_id', 'user_name', 'user_email'])
->where('users.is_suspended', '=', 'no');
}])
->where('articles.article_id', '=', 9)
->where('articles.is_published', '=', 1)
->get();
在这种情况下我会得到下一个结果:
[
{
article_id: 9,
user_id: 1,
article_title: "Article title here",
article_body: "Article body here",
is_published: 1,
created_at: "2015-01-17 02:26:24",
updated_at: "2015-01-17 02:26:24",
user: null
}
]
即使用户被挂起,它也会获取文章的数据,这是错误的。所以我的问题是如何修复第二个代码使其像第一个代码一样?
您可能想使用 with
来确保延迟加载关系,但您对其施加的任何约束仅适用于加载的关系。要限制对用户未暂停的文章的响应,您需要使用 whereHas
方法。
$articles = Article::with(['user' => function($q){
$q->select(['user_id', 'user_name', 'user_email', 'created_at']);
}])
->whereHas('user', function($q) {
$q->where('is_suspended', '=', 'no');
})
->where('articles.article_id', '=', 9)
->where('articles.is_published', '=', 1)
->get();
你需要 whereHas
而不是 with
(或两者都需要,但在这种情况下不需要 with
),就像@DavidBarker 说的那样。
但是我建议更多,请考虑这段代码的可读性:
$article = Article::whereHas('user', function ($q) {
$q->active();
})->published()->find(9);
它利用了scopes。
因此,您可以采取以下措施让您的生活更轻松:
将
is_suspended
更改为bool
因为:$user->is_suspended; // no (bool) $user->is_suspended; // true
在
User
模型上定义范围suspended
并在Article
上定义范围published
:// Article model - on User accordingly public function scopePublished($query) { $query->where('is_published', 1); }
当你想获取单个模型时使用
find($id)
或where('col', $id)->first()
而不是get
,因为后者会return一个集合,甚至虽然只有一个结果。