ソフトデリート設定済みのitemsテーブルとitem_childrenテーブルが存在し、こんなリレーションを設定したとして
items item_children
id -----┐ id
└------- item_id
name
items.id=1に紐づくitem_childrenのレコードを抽出し、item_children.nameを列挙する場合
(実際にはこんなコードは書かないけど、例ということで。)
以下のようにすれば取得することができる。
$items = Item::from('items')
->select(
'item_children.name',
)
->join('item_children', 'items.id', '=', 'item_children.item_id')
->where('items.id', '=', 1)
->whereNull('item_children.deleted_at') // 自力でやらないとダメ
->get();
結合した表のソフトデリートレコードを除く処理は自力でやらないとダメ
しかし、列名をつけると
$items = Item::from('items as i')
->select(
'ic.name',
)
->join('item_children as ic', 'i.id', '=', 'ic.item_id')
->where('i.id', '=', 1)
->get();
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'items.deleted_at'
というエラーが発生してしまう。
発行されたSQLは以下のようになっており
select
`ic`.`name`
from
`items` as `i`
inner join
`item_children` as `ic`
on `i`.`id` = `ic`.`item_id`
where
`i`.`id` = ?
and `items`.`deleted_at` is null
ソフトデリート済みのレコードを除く”items.deleted_at is null”が別名ではなく、テーブル名になっているからである。
これを回避するには
$items = Item::from('items as i')
->select(
'ic.name',
)
->join('item_children as ic', 'i.id', '=', 'ic.item_id')
->where('i.id', '=', 1)
->withTrashed('items') // 追加
->whereNull('i.deleted_at') // 自前でソフトデリート済みレコードを除く
->whereNull('ic.deleted_at') // 自前でソフトデリート済みレコードを除く
->get();
->withTrashed(‘items’)を記述して、items.deleted_at is nullを展開されるのを防ぎ、とりあえずソフトデリート済みのレコードも対象として、自前でwhereNull()によりソフトデリート済みレコードを除く処理にする必要がある。
結論は、リレーションのある構成ではソフトデリート機能は使わない方が良いと思う。
他にスマートなやり方や正しい方法があれば教えていただきたい^^