6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

DoctrineのLEFT JOINはまともに使えない

Last updated at Posted at 2014-08-25

DISTINCT / LEFT JOIN

schema.yml
TableA:
  actAs:
    Timestampable: ~
  columns:
    columna:
      type: string(255)

TableB:
  actAs:
    Timestampable: ~
  columns:
    columnb:
      type: string(255)
  relations:
    TableA:
      local: a_id
      foreign: id
      type: one
      foreignType: many

テーブルAとBに1対多のリレーションをはっておく。

	$data = Doctrine_Query::create()->from('TableA a')->leftJoin('a.TableB b')->limit(5)->execute();

	// Expected result : SELECT * FROM TableA a LEFT JOIN TableB b ON a.id = b.a_id LIMIT 5
	// Actual result : SELECT * FROM TableA a LEFT JOIN TableB b ON a.id = b.a_id WHERE a.id IN (1,2,3,4,5)

全体に掛けていたはずのLIMIT 5が、『テーブルAの件数が5件』という意味に勝手に書き換えられている。
ふざけてるの?

このファッキンな挙動を止める術は一応あって、

	$q = Doctrine_Query::create()->from('TableA a')->leftJoin('a.TableB b')->limit(5);
	$q->setDisableLimitSubquery(true);
	$data = $q->execute();

で余計な変換をせず想定したとおりのLIMITがかかります。
何故こちらがデフォルトでないのか理解に苦しむ。
あと返り値がbooleanなのでメソッドチェーンできない。

さて、これでめでたしかと思えば実はそんなことはない。
帰ってくるデータは実際はDoctrine_Collectionですが、配列として示すとこんなかんじになっています。

	$data = [
		0=>[
			id=>1,
			TableB=>[
				0=>[],
				1=>[],
				2=>[],
			]
		],
		1=>[
			id=>2,
			TableB=>[]
		],
		
	];

テーブルBが、同じa_id毎にまとめられてしまうのだ。
これはこれで便利な機能ではあるのですが、問題はこの挙動をやめさせる手段がないことです。

executeの引数で、返り値の形をある程度変更できます。

	// デフォルト、入れ子のDoctrine_Collectionで取得
	$data = $q->execute(array(), Doctrine_Core::HYDRATE_RECORD);
	// 入れ子の配列で取得
	$data = $q->execute(array(), Doctrine_Core::HYDRATE_ARRAY);
	// フラットな配列で取得
	$data = $q->execute(array(), Doctrine_Core::HYDRATE_ARRAY_SHALLOW);

配列ならフラットな形で取得できるのですが、何故かフラットなDoctrine_Collectionで取得する方法が無い。
素直にforeachループ一回で全TableBを扱わせろ。

6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?