lycheejam's tech log

チラ裏のメモ帳 | プログラミングは苦手、インフラが得意なつもり。

EntityFrameworkでテーブルがコミットされていなかった

概要

書いていたコードでテーブルに対してUPDATEをかけてCOMMITまでいってると思っていたら
UPDATE文が発行されておらずCOMMITもされていなかったメモ

対象のオブジェクトはオブジェクトの中にListを持っていて
EntityFrameworkので作成されるDBのテーブル的にはオブジェクト用のテーブルとさらにList用のテーブルの2つがあります。
2つまとめて1つのオブジェクトとして扱っていたのでUPDATE文が発行されていなかったオチです。

設計が悪いだのみたいなところには触れないでください。

環境

事象

  1. ツイートを行う。このときのツイートをAとする。
    • このときツイートAのツイートID(Twitter上でユニークなID)は後述されるテーブルに格納される。
  2. ツイートAに対して返信(リプライ)の形式でツイートBを飛ばす。
    • この時、ツイートAのツイートIDがツイートBのツイートIDに更新される。
  3. 以下ツイートが増えるごとに2の繰り返し

上記の動きがイメージするものでしたがツイートIDが更新されず
何回ツイートしても一番最初にツイートされたツイートAにメンションされている状態となっていました。

登場人物(オブジェクト)

public class TweetResult
{
    public int id { get; set; } //EFにて自動でIndexが付与される
    public string userId { get; set; } //アプリケーション内でユーザを特定する一意のID
    public long tweetId { get; set; } //前述のツイートID
    public List<MyTask> myTasks { get; set; }
}
public class MyTask {
    public int id { get; set; }
    public string myTask { get; set; }
    public int state { get; set; }
    //EFの機能でTweetResultからMyTaskを特定するためのIDがテーブルに追加されている。
}

修正前

//タスクのステータス更新とツイートID(リプライ先)の更新
public int UpdateTask(TweetResult tr) {
    using (MyContext db = new MyContext()) {
        var tresult = db.TweetResults.Where(x => x.id == tr.id)
                                 .Include("MyTasks")
                                 .SingleOrDefault();
        tresult = tr; //問題の部分
        db.SaveChanges(); //コミット
        return 0;   //正常終了値のつもり
    }
}

TweetResultテーブルから件のレコードを特定し、引数で渡されたオブジェクトを突っ込んで
そのままコミットしている”つもり”でした。

デバッグ画面でオブジェクトにちゃんと引数で渡しているオブジェクトに新しいツイートIDを入れていて値も確認しているのに更新された値は元のままで「なんでだ????」状態でした。

SQLログを確認したところUPDATE文が発行されていませんでした。
ここでハッと気付き、テーブルが2つあるからUPDATE文が発行されていない説を試しました。

メモ:SQLログの確認方法

下記を任意の場所に記述

db.Database.Log = (log) => Debug.WriteLine(log);

修正後

//タスクのステータス更新とツイートID(リプライ先)の更新
public int UpdateTask(TweetResult tr) {
    using (MyContext db = new MyContext()) {
        var tresult = db.TweetResults.Where(x => x.id == tr.id)
                                 .Include("MyTasks")
                                 .SingleOrDefault();
        tresult.myTasks = tr.myTasks; //修正
        tresult.tweetId = tr.tweetId; //修正
        db.SaveChanges(); //コミット
        return 0;   //正常終了値のつもり
    }
}

上記コードのようにテーブルごとにデータを格納したところ
以下のようなログが発行されコミットが確認出来ました。

2018/04/25 1:19:10 +09:00 で接続を開きました
2018/04/25 1:19:10 +09:00 でトランザクションを開始しました
UPDATE [dbo].[MyTasks]
SET [TweetResult_id] = NULL
WHERE (([id] = @0) AND ([TweetResult_id] = @1))
...省略
-- 1 ミリ秒で完了しました。結果: 1
UPDATE [dbo].[TweetResults]
SET [tweetId] = @0
WHERE ([id] = @1)
...省略
-- 0 ミリ秒で完了しました。結果: 1
...省略
2018/04/25 1:19:10 +09:00 でトランザクションをコミットしました
2018/04/25 1:19:10 +09:00 で接続を閉じました

テーブルデータの確認も行い
Twitterにてメンションが連なる様子も実際に確認できました。


雑感

デバッグ画面でちゃんと値が入ってんのになんだこりゃー状態でしたが
ログを確認するのも大事ですね。

GWを控えて今週は仕事でやる気が全く起きません。
いっぱい仕事があるのは嬉しいことなんですけどね。