如何在laravel中的嵌套关​​系上放置where条件?

Posted

技术标签:

【中文标题】如何在laravel中的嵌套关​​系上放置where条件?【英文标题】:How to put where condition on nested relation in laravel? 【发布时间】:2021-08-24 06:23:35 【问题描述】:

我有一张与consignmenthasMany有关系的发票

public function consignments_invoices()

    return $this->hasMany('App\Models\Admin\Consignment', 'invoice_id');

并且寄售与hasMany有关系Charge

public function charges()

    return $this->hasMany('App\Models\Admin\Charge', 'object_id')->where('model', 'Consignment');

charge这里我想把where子句放在属性rate_zone_id

我怎样才能做到这一点?

我有类似的现有查询

Invoice
    ::when(!empty($request->customer_id), function ($q) use ($request) 
        return $q->where('customer_id', $request->customer_id);
    )
    ->where('start_date', '>=', $request->start_date)
    ->whereDate('end_date', '<=', $request->end_date)
    ->with('consignments_invoices')->
    ->when(!empty($request->rate_zone_id), function ($q) use ($request) 
        //Here is want to use where condition on rate zone id
    )
    ->get();

【问题讨论】:

【参考方案1】:

为此,您可以使用whereHas()。 whereHas() 可以使用点表示法 (consignments_invoices.charges) 进行嵌套关系,因此您会得到如下内容:

$query->whereHas('consignments_invoices.charges', function ($query) use ($request) 
    $query->where('rate_zone_id', $request->rate_zone_id);
);

此外,when() 将第一个参数作为第二个参数传递给回调,因此您可以有类似的内容:

->when($request->rate_zone_id, function ($q, $rateZoneId) 
    $q->whereHas('consignments_invoices.charges', function ($q) use ($rateZoneId) 
        $q->where('rate_zone_id', $rateZoneId);
    );
)

这意味着整个查询看起来像:

Invoice
    ::when($request->customer_id, function ($q, $customerId)  
        return $q->where('customer_id', $customerId);
    )
    ->when($request->rate_zone_id, function ($q, $rateZoneId) 
        $q->whereHas('consignments_invoices.charges', function ($q) use ($rateZoneId) 
            $q->where('rate_zone_id', $rateZoneId);
        );
    )
    ->where('start_date', '>=', $request->start_date)
    ->whereDate('end_date', '<=', $request->end_date)
    ->get();

以上内容会将发票限制为特定的rate_zone_id(提供时),但不会限制consignments_invoices

为此,您还需要在 with() 调用中约束 consignments_invoices 关系:

->with([
    'consignments_invoices' => function ($query) use ($request) 
        $query->with('charges')->when($request->rate_zone_id, function ($q, $rateZoneId) 
            $q->whereHas('charges', function ($q) use ($rateZoneId) 
                $q->where('rate_zone_id', $rateZoneId);
            );
        );
    ,
])

这意味着您的整个查询将如下所示:

Invoice
    ::with([
        'consignments_invoices' => function ($query) use ($request) 
            $query->with('charges')->when($request->rate_zone_id, function ($q, $rateZoneId) 
                $q->whereHas('charges', function ($q) use ($rateZoneId) 
                    $q->where('rate_zone_id', $rateZoneId);
                );
            );
        ,
    ])
    ->when($request->customer_id, function ($q, $customerId)  
        return $q->where('customer_id', $customerId);
    )
    ->when($request->rate_zone_id, function ($q, $rateZoneId) 
        $q->whereHas('consignments_invoices.charges', function ($q) use ($rateZoneId) 
            $q->where('rate_zone_id', $rateZoneId);
        );
    )
    ->where('start_date', '>=', $request->start_date)
    ->whereDate('end_date', '<=', $request->end_date)
    ->get()

【讨论】:

它可以工作,但它也在获取那些没有 rate_zone_id 的货物 如果一个托运的费用具有正确的 rate_zone_id,它正在获取所有托运 @BilalArshad 您在哪里/如何装载货物?我在你原来的问题中没有看到这一点。 @BilalArshad 您是否也要承担费用? @BilalArshad 这回答了你的问题吗?如果是这样,请您将其标记为已接受:)【参考方案2】:

你可以使用嵌套关系

 Invoice::when(!empty($request->customer_id), function ($q) use ($request) 
        return $q->where('customer_id', $request->customer_id);
    )->where('start_date', '>=', $request->start_date)->whereDate('end_date', '<=', $request->end_date)
        ->when(!empty($request->rate_zone_id), function ($q) use ($request) 
            $q->whereHas('consignments_invoices.charges',function ($query) use ($request)
                $query->where('rate_zone_id',$request->rate_zone_id);
            );
        )->get();

【讨论】:

如果一个托运的费用具有正确的 rate_zone_id 它正在获取其所有托运 Invoice::when(!empty($request->customer_id), function ($q) use ($request) return $q->where('customer_id', $request->customer_id ); )->where('start_date', '>=', $request->start_date)->whereDate('end_date', 'end_date) ->whereHas('consignments_invoices') ->when(!empty($request->rate_zone_id), function ($q) use ($request) $q->whereHas('consignments_invoices.charges',function ($query) use ($request) $query ->where('rate_zone_id',$request->rate_zone_id); ); )->get();【参考方案3】:
$invoice = Invoice::with('charges')
            ->when(!empty($request->customer_id), function ($q) use ($request) 
                return $q->where('customer_id', $request->customer_id);
            )
            ->whereDate('start_date', '>=', $request->start_date)
            ->whereDate('end_date', '<=', $request->end_date);
    if (!empty($request->rate_zone_id)) 
        $invoice->whereHas('charges', function ($query1)use($request) 
            $query1->where('rate_zone_id', $request->rate_zone_id);
        );
    
    $invoices = $invoice->get()->toArray();

或者

$invoices = Invoice::with('charges')
                    ->when(!empty($request->customer_id), function ($q) use ($request) 
                        return $q->where('customer_id', $request->customer_id);
                    )
                    ->whereDate('start_date', '>=', $request->start_date)
                    ->whereDate('end_date', '<=', $request->end_date)
                    ->when(!empty($request->rate_zone_id), function ($query1) use ($request) 
                        $rate_zone_id = $request->rate_zone_id;
                        $query1->whereHas('charges', function ($query2)use($rate_zone_id) 
                            $query2->where('rate_zone_id', $rate_zone_id );
                        );
                    )->get()->toArray();



$invoice = Invoice::when(!empty($request->customer_id), function ($q) use ($request) 
                return $q->where('customer_id', $request->customer_id);
            )
            ->whereDate('start_date', '>=', $request->start_date)
            ->whereDate('end_date', '<=', $request->end_date);
    if (!empty($request->rate_zone_id)) 
        $rate_zone_id = $request->rate_zone_id;
        $invoice->with(['charges', function ($query1)use($rate_zone_id) 
                $query1->where('rate_zone_id', $rate_zone_id);
            ]);
    
    $invoices = $invoice->get()->toArray();

使用 whereHas=> https://laravel.com/docs/8.x/eloquent-relationships#querying-relationship-existence

【讨论】:

如果一个托运的费用具有正确的 rate_zone_id 它正在获取其所有托运 好的,那么在这种情况下,还可以通过急切加载添加条件 $invoice = Invoice::when(!empty($request->customer_id), function ($q) use ($request) return $q->where('customer_id', $request ->customer_id); ) ->whereDate('start_date', '>=', $request->start_date) ->whereDate('end_date', 'end_date); if (!empty($request->rate_zone_id)) $invoice->with('charges', function ($query1)use($request) $query1->where('rate_zone_id', $request->rate_zone_id) ; ); $invoices = $invoice->get()->toArray(); 还是一样的结果 rate_zone_id 单个还是多个?

以上是关于如何在laravel中的嵌套关​​系上放置where条件?的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 数据表搜索嵌套关系

如何使用 Room 中的嵌套关​​系

如何获取嵌套在laravel中的json

如何更新嵌套 Laravel 集合中的嵌套值

如何避免 laravel(php) 中的嵌套查询?

如何使用关系在laravel中的数据库中插入嵌套的二维数组