SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry
Laravelで、多対多のリレーションテーブルの中間テーブルを更新しようとすると、Integrity constraint violation: 1062 Duplicate entry~~~~~~というエラーが出て、進まない。
具体的には、商品にtag付けをするような仕組みで、
商品更新時に起こる。
商品情報の登録画面にTag登録画面もあり、そこにTagを#でつなぎ入力していく。
入力したTagが新しいものであれば、Tagテーブルに挿入(Tags)、商品テーブル更新(Items)、中間テーブル(Item_Tag)に当該商品のタグを追加する。
といったもの。
エラーの原因は重複!
落ち着いて考えればわかりそうだけど、単純に重複しているだけだった。
Laravelでマイグレーションするときに、この中間テーブルには、tag_idとitem_idの組み合わせでユニークな複合キーとする設定にしてあった。
もともと登録されているTagが「#元気 #かわいい #おもてなし」だとして、中間テーブル的には
#tag_id=1 item_id=20 name元気
#tag_id=2 item_id=20 nameかわいい
#tag_id=3 item_id=20 nameおもてなし
と入っているとして、情報の更新で
「#元気 #かわいい #おもてなし #すてき」として「すてき」を追加したい場合、中間テーブルに挿入する情報は
#tag_id=1 item_id=20 name元気
#tag_id=2 item_id=20 nameかわいい
#tag_id=3 item_id=20 nameおもてなし
#tag_id=4 item_id=20 nameすてき
となる。
リレーションを指定しているtag()メソッドを通してattach()してみると、表題のエラーが起こる。
$data->tag()->attach($tags_id);
そこで、一度、item_idのデータを全削除すればいっかと適当に削除を試みる。
$data->tag()->where('item_id', request('id'))->delete();//すでに登録のあるものを全部削除
しかしSQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint failsというエラーに見舞われる。
外部キー制約にひっかかってしまう。
外部キー制約をつけておきながらなんだけど、外部キー制約のことも、Laravelの多対多リレーション操作についてもあまりよく理解できていないため、ドキュメントを見てみると、sync()というメソッドですべて解決できそうだった。
多対多の関連を構築するためにsyncメソッドも使用できます。syncメソッドへは中間テーブルに設置しておくIDの配列を渡します。その配列に指定されなかったIDは中間テーブルから削除されます。ですからこの操作が完了すると、中間テーブルには配列中のIDだけが存在することになります。
https://readouble.com/laravel/6.x/ja/eloquent-relationships.html#many-to-many-polymorphic-relations
要するに、削除と追加を同時にしてくれるってことらしい。
ということで、発生していたエラーは、
$data->tag()->sync($tags_id);
で解決できた。
逆に新規登録時は
$data->tag()->attach($tags_id);
じゃないとエラーになる。あたりまえだけど・・・
めちゃくちゃ便利!!!!!
あぁ。。。勉強不足すぎて何が分かっていないかもわからない状態だ
コメントを残す