所以我的应用程序有这样的结构。
我想查询特定用户ID的所有付款(和数据透视数据)。我一直在使用此查询返回所有付款,无论user_id:
$payment_data = Payment::with('payers')->get();
现在,如果我只想获得付款人的user_id为5的付款,我试过这个:
$payment_data = Payment::with(array(
'payers' => function($q){
$q->where('user_id', '=', 5);
}))->get();
但它返回几乎相同的结果,除了条件仅适用于付款人,而不是付款,即我仍然在付款表中获得所有付款,而不是如果{{1条件未得到满足。从技术上讲,我可以使用此结果并过滤掉user_id
子数组为空的那些结果,但是对于大量付款,这将变得非常低效。
形成此查询的正确方法是什么?
以下是我的数据库结构的基本表示:
纯SQL查询就是这样的(RDMS各不相同,但你明白了):
payers
使用SELECT payments.*, payers_payments.*
FROM payments
RIGHT JOIN (payers
LEFT JOIN payers_payments
ON payers.id = payers_payments.payer_id)
ON payments.id = payers_payments.payment_id
WHERE payers.user_id = 5;
会得到以下结果:
wherehas
这不是我想要的。
好吧,经过多次摆弄,我知道我需要使用急切加载,因为我需要数据透视字段以及支付模型本身的字段。以下是显示3笔付款及其支点数据的示例:
SELECT *
FROM "payments"
WHERE (SELECT Count(*)
FROM "payers"
INNER JOIN "payer_payment"
ON "payers"."id" = "payer_payment"."payer_id"
WHERE "payer_payment"."payment_id" = "payments"."id"
AND "payers"."user_id" = '1') >= '1'
问题是,如果我然后将user_id条件更改为99999(不存在),它仍会返回所有带有Array
(
[0] => Array
(
[id] => 2
[payment_date] => 2014-03-07
[company] => Franco Manca
[item] => Pizza
[created_at] => 2014-03-10 10:16:08
[updated_at] => 2014-03-10 10:16:08
[payers] => Array
(
[0] => Array
(
[id] => 1
[name] => tim
[email] => tim@tim.com
[user_id] => 1
[created_at] => 2014-03-10 10:07:23
[updated_at] => 2014-03-10 10:07:23
[pivot] => Array
(
[payment_id] => 2
[payer_id] => 1
[amount] => 21.0
[pays] => 0
[created_at] => 2014-03-10 10:16:08
[updated_at] => 2014-03-10 10:27:45
)
)
[1] => Array
(
[id] => 2
[name] => tom
[email] => tom@tom.com
[user_id] => 1
[created_at] => 2014-03-10 10:16:35
[updated_at] => 2014-03-10 10:16:35
[pivot] => Array
(
[payment_id] => 2
[payer_id] => 2
[amount] => 0.0
[pays] => 1
[created_at] => 2014-03-10 10:27:45
[updated_at] => 2014-03-10 10:27:45
)
)
)
)
[1] => Array
(
[id] => 3
[payment_date] => 2014-03-05
[company] => Kaff
[item] => Cocktail
[created_at] => 2014-03-10 10:17:05
[updated_at] => 2014-03-10 10:17:05
[payers] => Array
(
[0] => Array
(
[id] => 1
[name] => tim
[email] => tim@tim.com
[user_id] => 1
[created_at] => 2014-03-10 10:07:23
[updated_at] => 2014-03-10 10:07:23
[pivot] => Array
(
[payment_id] => 3
[payer_id] => 1
[amount] => 12.0
[pays] => 1
[created_at] => 2014-03-10 10:17:05
[updated_at] => 2014-03-10 10:17:05
)
)
[1] => Array
(
[id] => 2
[name] => tom
[email] => tom@tom.com
[user_id] => 1
[created_at] => 2014-03-10 10:16:35
[updated_at] => 2014-03-10 10:16:35
[pivot] => Array
(
[payment_id] => 3
[payer_id] => 2
[amount] => 19.0
[pays] => 1
[created_at] => 2014-03-10 10:17:05
[updated_at] => 2014-03-10 10:17:05
)
)
)
)
)
数组的付款,每个付款都为空,事实上它应该返回一个完全空的结果。
为热切加载生成的2个查询是:
payers
和
select * from "payments" --I want to add my user_id condition to this
答案 0 :(得分:0)
方法 with 仅用于急切加载关系,对该关系的约束应该设置如下:
$payment_data = Payment::whereHas('payers', function($q){
$q->where('payers.user_id', '=', 5);
})->get();
);
您还可以在 where 子句中指定要使用的变量:
$payment_data = Payment::whereHas('payers', function($q) use ($foo){
$q->where('payers.user_id', '=', $foo);
})->get();
);
答案 1 :(得分:0)
尝试相反的方式
User::find(5)->with('payers.payments')->get();
你将有一个与你的付款人及其付款的课程,以便获得他们循环所需的一切,我认为加入可以完美地完成这项工作,因为你不需要循环。
答案 2 :(得分:0)
好的,经过广泛的搜索,problem with eloquent + sqlite我得到了答案:
您需要先使用whereHas
$payments = Payment::whereHas('payers', function($q){
$q->where('user_id', '=', Auth::user()->id);
},'>=', DB::raw('1'))->get();
然后,不要在整个Payment
模型上调用热切加载,而只需在刚刚创建的付款集合上调用它(懒惰的急切加载):
$payment_data = $payments->load(array(
'payers' => function($q){
$q->where('user_id', '=', Auth::user()->id);
}));
这会将支点数据添加到您的$ payments系列,为您提供所需的功能,而无需查询数据库中的每笔付款,这是问题中的第一种方法。