質問: EntityFrameworkCoreにてSQLiteを使用したWPFアプリケーションを作成しています。 ソースを下記GitHubにアップしましたので、ローカルにて実行して頂くと 現象が分かりやすいかと思います。 まず、各日付ごとにプロダクトがあり、その中にワークと作業時間があります。 そこで下記の手順を実行します。 1任意の日付にプロダクトを追加します。(画面右上「Add Product」を選択して任意のコード、名前を入力) 2追加されたプロダクト内にワークを追加します。(Productにマウスオーバーで現れる「Add Work」を選択) 3プルダウンから任意の大項目を選択。(ワーク内一番左) 4プルダウンから任意の小項目を選択。(ワーク内中央) 5Ctrl+Sで保存 6アプリケーションを一度終了して再起動 7手順234を再度すべて同じ項目で入力する 8Ctrl+Sで保存 ここで以下のエラーが発生します。 発生個所は「40_DataBase\DataBase.cs」内の89行目「db.Add(monthInfo);」部分です。 ``` The instance of entity type 'Work' cannot be tracked because another instance with the same key value for {'Index'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values. ``` しかし、手順6の再起動を行わなかった場合、同じワークを追加してもエラーは発生しません。 多対多テーブルの対象はProduct, Workで結合テーブル「ProductWork」を用いています。 アプリ再起動を行った場合、行わなかった場合で振る舞いが変わってしまう原因が 全く理解できず、エラー発生の理由が掴めない為、ご教示お願いします。
回答: データベースやEntityFrameworkに触れたことは無いので、トンデモな内容かもしれませんが、何かのヒントになれば。 元の処理的には、同じ内容のものがあるか検索して、有ったら削除してから、今回のものを追加する、と言う風になっていると見ました。 ここで今回は、追加する時点の`db.Add()`で例外になっている訳ですが、上記の処理を行うなら`db.Update()`に変えても良いのでは?と考えました。 実験したらそれでも例外が発生したので、何か類似の代替手段は無いかとIntellisenseで眺めていたら`Attach()`と言うのがあったので例外時にはそちらに切り替えてみたら、それらしく動作するようになりました。 以下のような感じですね。 元々の`var sel = db.MonthInfos`から`db.Add(monthInfo);`までの処理は削除しています。 ``` public static void SaveMonthInfo(MonthInfo monthInfo, bool isNotify = true) { try { using (var db = new Context()) { try { db.Update(monthInfo); } catch { db.Attach(monthInfo); } foreach (var item in db.Works) { db.Entry(item).State = EntityState.Detached; } db.SaveChanges(); } if (isNotify) Notification.Notify($"{monthInfo.Year}年{monthInfo.Month}月のデータを保存しました"); } catch (Exception e) { Debug.WriteLine(e.TargetSite.Name); Debug.WriteLine(e.Message); if (isNotify) Notification.Notify("データの保存に失敗しました"); } } ``` 知識や理論は何も無く、変えてみたら動くようになったレベルですが、興味を引いたら調べてみてください。