Nette框架-Nette\Database\ResultSet只实现单向迭代器



我遇到了foreach的一个问题。如果在第一个foreach{foreach $children as $child}中返回一个结果,则它有效。随着数量的增加,会弹出一个错误:NetteDatabaseResultSet仅实现单向迭代器。

该错误可能是由在同一表childern中查询的第一个($children(和第二个($invoices(foreach引起的。我需要列出所有子项(例如$child->firstName(,并为每个子项分配项目(例如$invoice->date$invoice->snackName(。然而,我不能取消";CCD_ 9";在查询中。

输出:

子项1名称

  • 项目1
  • 项目2

子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;
}

Latte

{block content}
{foreach $children as $child}
{$child->fisrtName}
{foreach $invoices as $invoice}
{invoice->snack}
{/foreach}
{/foreach}
{/block}

您的推理是正确的。大多数NetteDatabase方法返回的ResultSet是单向迭代器,因此不能在循环体的多次执行中使用它。这是一种优化——一旦循环推进迭代器,前一行可能会被垃圾收集,这对于节省大型数据库表的内存非常有用。

如果你真的需要多次迭代一个表,你可以:

  • 多次创建$invoices
    • 可能将整个赋值移动到模板内的循环中
    • 或者创建返回该结果并在模板中调用的函数
  • 或者例如通过将整个ResultSet转换成阵列来将其加载到存储器中。这也是文档建议的内容:

    ResultSet上只能迭代一次,如果我们需要迭代多次,则需要通过fetchAll()方法将结果转换为数组。

但如果可能的话,最好的解决方案是将其修复为使用JOINs。如果在数据库中使用FOREIGN KEYS,则可以避免编写原始SQL,并使用更好的接口,当您尝试通过具有外键约束的列访问其他表中的数据时,该接口将透明高效地为您创建JOIN

最新更新