prefetch(multi)した際は、order_byに気をつけること。
$schema->resultset('Area')->search( { }, { prefetch => 'prefectures', } );
この場合DBICはイテレータ、AreaとArea->Prefecturesに付随するデータをSQL一文で取得するわけです。
prefecturesはareaにとってhas_many(multi)です。
SQLはこんなかんじ。
SELECT me.id, me.name, prefectures.id, prefectures.hira_name, prefectures.name, prefectures.ascii_name, prefectures.abbr_name, prefectures.area_id, prefectures.position FROM area me LEFT JOIN prefecture prefectures ON ( prefectures.area_id = me.id ) ORDER BY prefectures.area_id
order_byが自動的に付加されています。DBICがArea->Prefecturesのイテレータを構築しやすいようにだと思われます。
結果
ハマるポイントはorder_byを指定した場合。上のを基にしてみます。
$schema->resultset('Area')->search( { }, { prefetch => 'prefectures', order_by => 'prefectures.id', } );
これでAreaイテレータを $area_rs->next とやっていくと
問題がおこります。(素直というべきか・・・)
SQLはこんなかんじ。
SELECT me.id, me.name, prefectures.id, prefectures.hira_name, prefectures.name, prefectures.ascii_name, prefectures.abbr_name, prefectures.area_id, prefectures.position FROM area me LEFT JOIN prefecture prefectures ON ( prefectures.area_id = me.id ) ORDER BY prefectures.id, prefectures.area_id
ORDER BY prefectures.id, prefectures.area_id ではDBICがイテレータを構築するに期待していない並びで結果が返ってしまいます。
つられて $area_rs->next が 1 -> 2 -> 3 -> 2 -> 3 昇ったり降りたりするんです。
正解は
$schema->resultset('Area')->search( { }, { prefetch => 'prefectures', order_by => ['me.id'. 'prefectures.id'], } );
prefetch(multi) & order_byした際は、DBICがイテレータを構築しやすいように、配慮してあげること。