Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Laravel Eloquentで複数レコードが削除された話
Search
Rei
July 25, 2025
Programming
82
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Laravel Eloquentで複数レコードが削除された話
Rei
July 25, 2025
More Decks by Rei
See All by Rei
PHPで理解するストリーム処理
sonor04ls
0
77
Laravelで簡単リアルタイム通信
sonor04ls
0
79
Other Decks in Programming
See All in Programming
自作OSでスライド発表する
uyuki234
1
3.9k
SREは、MCPとSRE Agentをこう使え!
kazumax55
0
150
【やさしく解説 設計編 #0】DDDのコード、読めるのに分からない人へ
panda728
PRO
2
270
地域 SRE コミュニティ最前線 - ホンマでっかSRE勉強会
tk3fftk
0
250
任せる範囲はこう広がった / How the Scope of AI Delegation Has Expanded
nrslib
1
260
SREの積み重ねがAI駆動開発のガードレールになった ― 7つの実践/SRE Guardrails The 7
tomoyakitaura
8
4.5k
【SRE NEXT 2026 Lunch Session】一人目専任SREの立ち上げを加速する ― AIと進めたオンボーディングで2分を0.04秒にした話
pkshadeck
PRO
0
2.8k
Honoでのサプライチェーン侵害対策 〜 3つのライブラリに学ぶ
yusukebe
7
1.9k
Performance Engineering for Everyone
elenatanasoiu
0
270
ビデオ通話が繋がる0.2秒で何が起きているのか
supurazako
2
150
Claude Opus 4.6以後の受託開発エンジニアの変化(Claude Code開発ノウハウ大公開スペシャルbyクラスメソッド)
iidatakuma
1
800
トークンをケチるな、設計しろ:GitHub Copilotを賢く使うコンテキスト戦略
ochtum
0
320
Featured
See All Featured
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.3k
HU Berlin: Industrial-Strength Natural Language Processing with spaCy and Prodigy
inesmontani
PRO
0
540
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
201
75k
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.8k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
49
10k
Designing Powerful Visuals for Engaging Learning
tmiket
1
450
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
2
240
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
What the history of the web can teach us about the future of AI
inesmontani
PRO
1
640
Optimising Largest Contentful Paint
csswizardry
37
3.8k
Game over? The fight for quality and originality in the time of robots
wayneb77
1
220
Transcript
Laravel Eloquentで複数レコードが削除された話 〜本当にあった怖い話〜 1
問題のコード 商品レビューを1件削除したいだけなのに... // 商品ID「123」に対するユーザー「田中太郎」のレビューを削除したい $deleteTarget = ProductReview::where('product_id', 123) ->where('user_name', '田中太郎')
->first(); $deleteTarget->delete(); 結果: 想定していた1件ではなく複数のレビューが削除されてしまった 2
問題のあるDB構成 元々のテーブル設計(独自プライマリーキー) CREATE TABLE product_reviews ( review_id INT, -- プライマリーキー制約なし!
product_id INT, user_name VARCHAR(100), rating INT, comment TEXT, created_at TIMESTAMP ); 実際のデータ review_id product_id user_name rating comment 1 123 田中太郎 5 素晴らしい商品です 1 456 佐藤花子 4 普通に良いです 3
Eloquentモデルの設定 class ProductReview extends Model { protected $table = 'product_reviews';
protected $primaryKey = 'review_id'; // 独自のプライマリーキーを指定 public $incrementing = false; // AUTO_INCREMENTではない public $timestamps = false; } 問題: Eloquentは review_id をプライマリーキーとして認識しているが、DB側では制約がな い 4
何が起こったのか? Eloquentの delete() メソッドの内部動作: 1. 検索時: WHERE product_id = 123
AND user_name = '田中太郎' 2. 取得: review_id = 1 のレコードを取得 3. 削除時: WHERE review_id = 1 のみで削除実行 4. 結果: review_id = 1 を持つすべてのレコードが削除される // Eloquent内部で実行されるクエリ DELETE FROM product_reviews WHERE review_id = 1; → 田中太郎と佐藤花子の両方のレビューが削除! 5
Eloquentの内部実装を確認してみた namespace Illuminate\Database\Eloquent; public function delete() { $this->performDeleteOnModel(); return true;
} protected function performDeleteOnModel() { $this->setKeysForSaveQuery($this->newModelQuery())->delete(); } protected function setKeysForSaveQuery($query) { // 最初の検索条件は無視され、プライマリーキーのみが使用される $query->where($this->getKeyName(), '=', $this->getKeyForSaveQuery()); return $query; } 6
応急対処法 クエリビルダーを使用して明示的に条件指定 // 複数条件を明示的に指定 ProductReview::where('product_id', 123) ->where('user_name', '田中太郎') ->where('review_id', $targetReviewId)
->delete(); // または、LIMITを使用 ProductReview::where('product_id', 123) ->where('user_name', '田中太郎') ->limit(1) ->delete(); 注意: update() でも同様の問題が発生する可能性あり 7
根本的な解決策 Laravel標準の $table->id() を使用(最推奨) // マイグレーションファイル Schema::create('product_reviews', function (Blueprint $table)
{ $table->id(); // Laravel標準のid(確実にユニーク) $table->unsignedBigInteger('product_id'); $table->string('user_name'); $table->integer('rating'); $table->text('comment'); $table->index(['product_id', 'user_name']); }); 8
Laravel標準構成のメリット Eloquentモデル(デフォルト設定で十分) class ProductReview extends Model { protected $fillable =
['product_id', 'user_name', 'rating', 'comment']; // プライマリーキーは自動的に'id'になり、AUTO_INCREMENTが有効 } 生成されるテーブル CREATE TABLE product_reviews ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, -- 確実にユニーク product_id BIGINT UNSIGNED, user_name VARCHAR(255), rating INT, comment TEXT, ); 9
既存システムの移行方法 段階的な移行 // 移行用マイグレーション Schema::table('product_reviews', function (Blueprint $table) { $table->id()->first();
// Laravel標準のidカラムを追加 $table->dropPrimary('review_id'); // 古いプライマリーキーを削除 }); データ移行後、モデルを標準設定に変更 class ProductReview extends Model { // protected $primaryKey = 'review_id'; ← 削除 // public $incrementing = false; ← 削除 protected $fillable = ['product_id', 'user_name', 'rating', 'comment']; } 10
まとめ 重要なポイント Laravelを使うなら標準の $table->id() を使っておくのが最も無難 独自のプライマリーキー設計は予期しない問題を招きやすい Eloquentの動作原理を理解した上で使用する 重要な処理では複数パターンの動作確認を行う 教訓 フレームワークの標準に従うことで、多くの問題を未然に防げる
迷ったら Laravel の標準設定を使おう! 11