質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

1回答

2758閲覧

save()を使った1レコードの値の更新について

fromtasky

総合スコア5

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2020/03/08 12:20

編集2020/03/08 22:34

前提・実現したいこと

現在、スマートフォン向けのアプリを作成中です。
webのリクエストからDB内のデータを変更するプログラムを作成しています。

Laravelのコントローラ内の処理で、
テーブルからレコードを取得し、
その中の値を変更するプログラムを記述しました。

しかし、挙動が望ましくありません。

発生している問題・エラーメッセージ

・求めている結果
取得した1レコードのみ更新

・実際の結果
user_idに紐づいたstatusカラムの全ての値が
変更されている。

更新前
イメージ説明

更新後
イメージ説明

1.
ドキュメントによると、save()という挙動が、
「モデルの更新をする」という説明になっています。
https://readouble.com/laravel/6.x/ja/eloquent.html

私の考えの
取得したレコードを変数として与え、
その「1レコード部分の更新」という使い方は
できないものなのでしょうか。

2.
この1レコードを更新することを実現するには、
どのようなアプローチをすればよろしいでしょうか。

参考文献や、
知見がありましたら、

ご教授いただけますと幸いです。
よろしくお願いいたします。

該当のソースコード

---ソース(コントローラ)---

PHP

1public function Foo(Request $request){ 2 3 $user_id = $request->user_id; 4 $quest_id = $request->quest_id; 5 6 //user_questからクエスト取得 7 $user_quest = UserQuest::where('user_id', $user_id)->where('quest_id', $quest_id)->first(); 8 if (!$user_quest){ 9 return config('error.ERROR_INVALID_DATA'); 10 } 11 12 //値の変更 13 $user_quest->status = 3; 14 15 //DBの更新 16 try{ 17  $user_quest->save(); 18 } catch (\PDOException $e){ 19 return config('error.ERROR_DB_UPDATE'); 20 } 21 22 ~~ 23}

---モデル---------

PHP

1class UserQuest extends Model 2{ 3 // 4 protected $table = 'user_quest'; 5 public $incrementing = false; 6 protected $primaryKey = 'user_id'; //複数未対応 7 public $timestamps = false; 8}

---マイグレーション---

PHP

1 public function up() 2 { 3 Schema::create('user_quest', function (Blueprint $table) { 4 $table->string('user_id', 37)->charset('utf8'); 5 $table->unsignedInteger('quest_id')->default(0); 6 $table->unsignedTinyInteger('status')->default(0); 7 $table->boolean('clear')->default(0); 8 $table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP')); 9 $table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP')); 10 $table->primary(array('user_id', 'quest_id')); 11 12 }); 13 }

試したこと

ドキュメントやブログを参考に
saveやupdateの挙動などを調べました。
問題を解決する根本の原因が特定できておりません。

補足情報(FW/ツールのバージョンなど)

####各種バージョン

・PHP
7.2.27

・Laravel
6.16.0

・MySQL
5.7.29

####参考書籍
「スタートアップ・個人で作れるスマホ向け Unityソーシャルゲーム開発ガイド」
https://www.shuwasystem.co.jp/book/9784798059389.html

###全体の処理の流れや、構成について

処理の流れは、
下記のようになっています。


①user側のテーブルからユーザidを取得し、
クライアント側に保持
(user_profileテーブル)後述

②取得したユーザidにクエストidの情報をつけて
quest(ユーザ側)のテーブルを更新 ←今回ご質問していた箇所
(user_questテーブル)

③quest(マスターデータ)側はJSONで取得し、
クライアント側で保持
(特に上記のサーバ側の箇所に干渉しない)


◆user側
利用するユーザ情報を定義しています。
・ユーザid
・ユーザ名

quest(ユーザ)側の「user_quest」テーブルと共通するユーザid(user_id)のカラムを持っていますが、
現状、サーバー側で「user_profile」テーブルと、「user_quest」テーブルを複合して
参照する処理はまだ追加していません。

テーブル名:user_profile

〇user_profileテーブル
---------マイグレーション----------
Schema::create('user_profile', function (Blueprint $table) {
$table->string('user_id',37)->charset('utf8');
$table->string('user_name',32)->charset('utf8');
$table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));
$table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP'));
});


◆quest(ユーザ)側
ユーザが持つ変動的なゲーム情報を定義しています。
・クエストクリア(未or済)
・クエスト状態(スタート、リタイア、クリア) など

テーブル名:user_quest
(↑今回ご質問したテーブル)

〇user_questテーブル
---------マイグレーション----------
Schema::create('user_quest', function (Blueprint $table) {
$table->string('user_id', 37)->charset('utf8');
$table->unsignedInteger('quest_id')->default(0);
$table->unsignedTinyInteger('status')->default(0);
$table->boolean('clear')->default(0);
$table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP'));
$table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP'));
$table->primary(array('user_id', 'quest_id'));

});

◆quest(マスターデータ)側
固定的なゲーム情報を定義しています。
(クエスト情報)
こちらはJSON形式で別に管理しています。

quest側の構成
・クエストid
・クエスト名   など

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2020/03/08 13:10

データベースのカラムを拝見すると、user と quest を多対多で結ぶための中間テーブルに見受けられますが、その辺りの説明が足りていませんので、説明ください。
kyoya0819

2020/03/08 13:18

これどこを参考に書かれていますか?
m.ts10806

2020/03/08 14:23

>[Laravel][PHP][MySQL] タイトルに含まなくてもタグで対応可能です。タイトルが冗長になるだけなので、タグで対応できるものはタグのみで対応してください。
fromtasky

2020/03/08 14:35

>m.ts10806 さん タイトルの件対応いたしました。
fromtasky

2020/03/08 22:32 編集

>Kosuke_Shibuya さん ご質問の意図に沿っていなかったら、すみません。 下記、説明を記載いたします。 〇そのあたりの全体の構成や流れについて (↑質問本文に記載しました)
kyoya0819

2020/03/08 16:32

Unityの本にLaravelが書かれているのでしょうか?
fromtasky

2020/03/08 16:43

>asuchi0819 さん はい、こちらの参考書籍は、サーバー側(AWSで作成したlinux上にLAMP環境を構築し、Laravelを使用したサーバー側)と、Unityを使用したクライアント側のやりとりについて記述されています。(本の内容としては、必要最低限の説明があり、細かくは調べてね・・というスタイルの本です) 本だったので、参考元のソースコードをペタっと張ることができませんでした。
m.ts10806

2020/03/08 21:31

様々な情報をこちらのコメント欄に書かれていますが、デフォルト非表示であるため目につきにくいしまとめて確認が難しいのです。 質問本文に記載してください。
fromtasky

2020/03/08 22:19

> m.ts10806 さん 不慣れですみませんでした。記載箇所移行します。
guest

回答1

0

ベストアンサー

UserQuestモデルでuser_idを主キーとして設定していますが、user_questテーブルのマイグレーションを見たところではuser_idquest_idの複合主キーで定義されています。ここが一致していないのが根本原因です。

Eloquentモデルは主キーとして設定されたカラムでレコードを一意に識別できるということを前提にしていますので、user_idのような一意に識別できないカラムを指定した場合は正しい動作は保証されません。おかしな設定でも特にエラーの検出はしてくれませんのでなんとなく実行されますが、同じuser_idquest_idが異なるカラムがある場合は全てが更新されてしまいます。(update ... where user_id = xxのようなsqlが実行されますので)

対処としてはEloquentモデルは複合主キーは扱えませんので、user_questテーブルについて別に自動インクリメントする整数のカラムを主キーとして用意し、user_idquest_idについてunique indexを作成するのがいいでしょう。

投稿2020/03/08 13:32

crhg

総合スコア1177

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fromtasky

2020/03/08 15:41

ご回答ありがとうございます。 再度マイグレーション作成を行い、検証してみます。
fromtasky

2020/03/08 22:21

ひとまず、いただいたアドバイスを参考に、 再度マイグレーションを作成し、やり直したところ、 1レコードの更新ができました。ありがとうございます。 解決方法、後ほど記載いたします。
fromtasky

2020/03/08 22:42

ありがとうございました。解決後の変更点を記載します。 おっしゃる通り、主キーの設定が原因でした。 もう少し、テーブル設計を検討・調整してみます。 --------- 主にuser_questテーブルの構成の以下を変更しました。 ・主キー:id 自動インクリメント ←新規に追加 ・user_id index付与 ・quest_id index付与 ----変更後のマイグレーション--- Schema::create('user_quest', function (Blueprint $table) { $table->increments('id'); $table->string('user_id', 37)->charset('utf8'); $table->unsignedInteger('quest_id')->default(0); $table->unsignedTinyInteger('status')->default(0); $table->boolean('clear')->default(0); $table->timestamp('created_at')->default(DB::raw('CURRENT_TIMESTAMP')); $table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP')); $table->index('user_id'); $table->index('quest_id'); });
crhg

2020/03/08 22:56

user_idとquest_idの同じ組み合わせは複数存在してはいけないから複合主キーにしていたのではないのでしょうか? その場合は組み合わせで複合uniqueインデックスにする必要があります。 $table->unique(['user_id', 'quest_id']);
fromtasky

2020/03/09 01:41

失礼いたしました。indexを指定していた前に、単体にuniqueを付与していたため、完全に複合とするところを間違えていました。 ご指摘の通り、複合uniqueインデックスにて、動作確認いたしました。 ありがとうございました。 ---削除--- $table->index('user_id'); $table->index('quest_id'); ---追記--- $table->unique(['user_id', 'quest_id']);
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問