Nette 框架 - Nette\Database\ResultSet 仅实现一种迭代器
Nette framework - Nette\Database\ResultSet implements only one way iterator
我遇到了 foreach 问题。
如果在第一个 foreach {foreach $children as $child}
中返回了一个结果,那么它就起作用了。多了就报错:
Nette\Database\ResultSet
只实现一种方式的迭代器。
错误可能是第一个($children
)和第二个($invoices
)foreach在同一个tablechildern
中被查询引起的。我需要列出所有 children(例如 $child->firstName
)并为每个分配项目(例如 $invoice->date
$invoice->snackName
)。但是,我无法取消查询中的“JOIN ON children
”。
输出:
child 1 个名字
- 项目 1
- 项目 2
child 2 姓名
- 项目 1
- 项目 2
不知道怎么了?
谢谢
public function actionShow($year, $month)
{
$invoices = $this->database->query('
SELECT
o.date AS date,
o.snack AS snack
FROM
diet_orders o
LEFT JOIN children ch ON o.child_id = ch.id
WHERE
ch.user_id = ?
and YEAR (o.date) = ?
and MONTH (o.date) = ?
', $this->getUser()->id, $year, $month,'');
$children = $this->database->table('children')->where('user_id = ?', $this->getUser()->id);
$this->template->invoices = $invoices;
$this->template->children = $children;
}
拿铁
{block content}
{foreach $children as $child}
{$child->fisrtName}
{foreach $invoices as $invoice}
{invoice->snack}
{/foreach}
{/foreach}
{/block}
你的推理是正确的。大多数 Nette\Database
方法返回的 ResultSet
是一种单向迭代器,因此您不能在循环体的多次执行中使用它。这是一种优化——一旦循环推进迭代器,前一行可能会被垃圾收集,这对于在大型数据库 tables.
上节省内存很有用
如果您确实需要多次迭代 table,您可以:
- 多次创建
$invoices
- 可能将整个赋值移动到模板内的循环中
- 或创建函数返回该结果并在模板中调用它
- 或将整个
ResultSet
加载到内存中,例如将其转换为数组。这也是 documentation 推荐的:
Over the ResultSet
is possible to iterate only once, if we need to iterate multiple times, it is necessary to convert the result to the array via fetchAll()
method.
但最好的解决方案是修复它以使用 JOIN
s,如果可能的话。如果您在数据库中使用 FOREIGN KEYS
,则可以避免编写原始 SQL 并使用 much nicer interface,当您尝试访问时,它会透明高效地为您创建 JOIN
通过具有外键约束的列来自其他 table 的数据。
我遇到了 foreach 问题。
如果在第一个 foreach {foreach $children as $child}
中返回了一个结果,那么它就起作用了。多了就报错:
Nette\Database\ResultSet
只实现一种方式的迭代器。
错误可能是第一个($children
)和第二个($invoices
)foreach在同一个tablechildern
中被查询引起的。我需要列出所有 children(例如 $child->firstName
)并为每个分配项目(例如 $invoice->date
$invoice->snackName
)。但是,我无法取消查询中的“JOIN ON children
”。
输出:
child 1 个名字
- 项目 1
- 项目 2
child 2 姓名
- 项目 1
- 项目 2
不知道怎么了? 谢谢
public function actionShow($year, $month)
{
$invoices = $this->database->query('
SELECT
o.date AS date,
o.snack AS snack
FROM
diet_orders o
LEFT JOIN children ch ON o.child_id = ch.id
WHERE
ch.user_id = ?
and YEAR (o.date) = ?
and MONTH (o.date) = ?
', $this->getUser()->id, $year, $month,'');
$children = $this->database->table('children')->where('user_id = ?', $this->getUser()->id);
$this->template->invoices = $invoices;
$this->template->children = $children;
}
拿铁
{block content}
{foreach $children as $child}
{$child->fisrtName}
{foreach $invoices as $invoice}
{invoice->snack}
{/foreach}
{/foreach}
{/block}
你的推理是正确的。大多数 Nette\Database
方法返回的 ResultSet
是一种单向迭代器,因此您不能在循环体的多次执行中使用它。这是一种优化——一旦循环推进迭代器,前一行可能会被垃圾收集,这对于在大型数据库 tables.
如果您确实需要多次迭代 table,您可以:
- 多次创建
$invoices
- 可能将整个赋值移动到模板内的循环中
- 或创建函数返回该结果并在模板中调用它
- 或将整个
ResultSet
加载到内存中,例如将其转换为数组。这也是 documentation 推荐的:Over the
ResultSet
is possible to iterate only once, if we need to iterate multiple times, it is necessary to convert the result to the array viafetchAll()
method.
但最好的解决方案是修复它以使用 JOIN
s,如果可能的话。如果您在数据库中使用 FOREIGN KEYS
,则可以避免编写原始 SQL 并使用 much nicer interface,当您尝试访问时,它会透明高效地为您创建 JOIN
通过具有外键约束的列来自其他 table 的数据。