Laravel的Eloquent ORM与查询生成器
问题描述:
我有2个表格:users
和articles
。 users
表具有名为is_suspended
的列,其接受yes
或no
,并且articles
表具有名为is_published
的列,其接受0
或1
。要从数据库中提取商品数据,articles.is_published
必须等于1
,而users.is_suspended
必须等于no
。现在假设users.is_suspended
等于yes
,如果我尝试使用查询生成器这样获取的文章的数据:Laravel的Eloquent ORM与查询生成器
// 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();
这将很好地工作,并且将返回任何结果(因为users.is_suspended
= yes
)。现在,让我们尝试获取与Laravel雄辩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
模型和published
定义范围suspended
上Article
:// Article model - on User accordingly public function scopePublished($query) { $query->where('is_published', 1); }
如果您想要获取单个模型,请使用
find($id)
或where('col', $id)->first()
而不是get
,因为后者将返回集合,即使只有一个结果。
这很好。但是,如何选择特定列和我应该放在哪里:select(['user_id','user_name','user_email'])。我曾试图这样做:$ q-> select(['user_id','user_name','user_email','created_at']) - > where('is_suspended','=','no');但它会导致错误:(基数违规:1241操作数应该包含4列)。 – Amr
为你添加它,你把它放在原来的位置,用'with'方法回调。 –
它导致错误说:explode()期望参数2是字符串,给定的对象。 – Amr