Laravel在急切的装载条件下查询了许多记录

时间:2014-03-10 11:16:22

标签: php sql laravel eloquent

所以我的应用程序有这样的结构。

  • 付款 hasAndBelongsToMany 付款人
  • 付款人所属用户用户 hasMany 付款人

我想查询特定用户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子数组为空的那些结果,但是对于大量付款,这将变得非常低效。

形成此查询的正确方法是什么?

修改

以下是我的数据库结构的基本表示:

enter image description here

纯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

这不是我想要的。

编辑2

好吧,经过多次摆弄,我知道我需要使用急切加载,因为我需要数据透视字段以及支付模型本身的字段。以下是显示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

3 个答案:

答案 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系列,为您提供所需的功能,而无需查询数据库中的每笔付款,这是问题中的第一种方法。