2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

C#とEntity Framework Coreでデータ更新していたら、ある日突然更新ができなくなった話。

Posted at

はじめに

C#とEntity Framework Coreでデータ更新を行う処理を作成し、数年間エラーなく処理が動いていたプログラムがありました。ある日、更新できず処理が止まってしまう事態となりました。

今回はその現象のプログラムと解決策をとなります。

問題となった処理

code.cs
Models.HogeDBContext db = new Models.HogeDBContext();

var items = db.V_Table                     // Viewテーブル
              .Where(r => r.hoge == hoge); // なんらかの条件式

foreach (var item in items)
{
    // なんらかの処理
    var data = db.T_Table
                 .Where(r => r.id == id); // idから1件データを取得
    if(data == null)
    {
        data = new T_Table {/* パラメータ追加 */}
        db.T_Table.Add(data);   
    }
    else
    {
        // dataの値を更新
        db.Entry(data).State = EntityState.Modified;
    }
    db.SaveChanges(); // ここで止まる
}

エラー内容

上記処理の db.SaveChanges() で止まり、初回は An error occurred while saving the entity changes. See the inner exception for details. が出力され、2回目以降は 新しいトランザクションは許可されません。他のスレッドがこのセッションで実行されています。 と出力され続けるようになりました。

原因の考察

データが日々増えてくる事でView V_Table のパフォーマンスが遅くなる事で発生していると考えました。
また、このViewは リンクテーブル もJOINしている事で一層のパフォーマンス低下を及ぼしていると思われます。

これらが原因でIQueryableとして取得されたデータを直接ループ内で操作してしまい、データベースへのアクセスが繰り返され、トランザクションや接続の問題が発生しやすくなったのだと考えます。

この部分(View)の変更はテストを含めると時間がかかるので以下の方法で解決しました。

解決策

ToArray()の使用

ToArray()メソッドを使用することで、クエリが即時実行され、結果が配列としてメモリ内に格納されます。クエリの実行がループの外で行われるため、遅延実行による問題も解消されます。

修正後のコードでは、ToArray()を使用してクエリを即時実行し、結果を配列として格納しています。これにより、データベースへのアクセスがループの外で一度だけ行われ、トランザクションの競合が発生しにくくなります。

code修正後.cs
var items = db.V_Table                     // Viewテーブル
              .Where(r => r.hoge == hoge)  // なんらかの条件式
              .ToArray();                  // ToArray()で必要なデータを取得

まとめ(教訓)

  • 遅延実行する必要が無いものはToArray()等で確定させる
2
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?