英文:
Laravel whereHas children in Blade template
问题
我目前拥有产品和时段的概念作为模型;一个时段是一个时间段,一个产品可以拥有一个或多个时段。
也就是说,一个产品可以拥有多个时段,举个例子如下:
产品 - "烹饪课"
时段 - ['2023-12-12 11:00:00', '2023-12-12 13:00:00']
我目前查询的方式如下:
Product::whereHas('slots', function ($query) {
$query->whereDate('start_time', '=', $this->booking_date);
})->get();
这个查询按预期工作,但在我的 Blade 模板中,当我想要列出可用的时段时,调用
{{$product->slots()}}
会根据模型中定义的关系获取所有时段,并不会注意到 WhereDate 子句 - 在我的 Blade 模板中,如何迭代给定产品的时段,并考虑到时段的 WhereDate 子句呢?理想情况下,我不想再为此编写另一个查询。
英文:
I currently have the concept of Products and Slots as Models; A Slot is a time slot, and a product can have 1 or many time slots.
That is to say that One Product can have many Slots. lay example being as below:
Product - "Cookery Class"
Slots - ['2023-12-12 11:00:00', '2023-12-12 13:00:00']
I currently query this like below:
Product::whereHas('slots' ,function ($query) {
$query->whereDate('start_time', '=', $this->booking_date);
})->get();
This works as expected, however inside my Blade template when I want to list the slots available calling
{{$product->slots()}}
Get's all slots as per the relationship defined in the Model and takes no notice of the WhereDate clause - how can I within my Blade template iterate through the slots for a given Product with the WhereDate clause of Slots. Ideally I don't want to write another query for this.
答案1
得分: 1
将->whereHas()
改为->withWhereHas()
:
$products = Product::withWhereHas('slots', function ($query) {
$query->whereDate('start_time', '=', $this->booking_date);
})->get();
这将"急切加载" slots
模型,并过滤您的 Product
记录,只保留满足嵌套的 ->whereDate()
子句的记录。
接下来,在您的 .blade.php
文件中,不要使用 ->slots()
。这有两个问题:
- 带括号的
->slots()
总是一个新的查询,完全忽略了通过->withWhereHas()
进行的急切加载。 ->slots()
的查询实际上没有执行,因此执行{{ $product->slots() }}
很可能什么都不会输出,或者如您所述,输出所有slot
记录,即使它们不满足您指定的->whereDate
子句。
它应该是这样的:
@foreach($product->slots()->get() as $slot)
{{ $slot }}
@endforeach
但再次强调,您不应该这样做,因为现在存在 N+1 查询问题,每次迭代 $products
都会执行一个新的查询,还有上述提到的其他问题。
您最终的 .blade.php
代码应该是这样的:
@foreach($products as $product)
@foreach($product->slots as $slot)
{{ $slot }}
@endforeach
@endforeach
英文:
Change ->whereHas()
to ->withWhereHas()
:
$products = Product::withWhereHas('slots' ,function ($query) {
$query->whereDate('start_time', '=', $this->booking_date);
})->get();
This will "Eager Load" the slots
Models, as well as filter your Product
records to only those that satisfy the nested ->whereDate()
clause.
Next, in your .blade.php
file, don't do ->slots()
. There's 2 issues with that:
->slots()
with()
is always a new query, and completely ignores the eager loading done via->withWhereHas()
- The query from
->slots()
isn't actually executed, so doing{{ $product->slots() }}
will likely output nothing, or, as you stated, allslot
records, even those that do not satisfy the->whereDate
clause you specified.
It would need to be:
@foreach($product->slots()->get() as $slot)
{{ $slot }}
@endforeach
But again, you wouldn't want to do this, as it's now an N+1 query issue, where each iteration of $products
executes a new query, along with the other issues mentioned above.
Your final .blade.php
code should be:
@foreach($products as $product)
@foreach($product->slots as $slot)
{{ $slot }}
@endforeach
@endforeach
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论