none
EntityFrameworkでリレーション先の多側テーブルのデータを削除したときのエラーについて その2 RRS feed

  • 質問

  • https://social.msdn.microsoft.com/Forums/ja-JP/cc695ac8-90f6-4273-8e33-d9c5a202052c/entityframework?forum=netfxgeneralja

    承前

    お世話になります。

    WPFやらMVVMやらが混じるのですがEntityFrameworkの動作の問題だと思うのでここで質問させていただきたいと思います。

    前回、多側テーブルのデータを削除したときに(追加や編集は行えるのに)エラーが発生するという質問をさせていただきました。その際は、gekkaさんに回答をいただきまして、その方法でWPFアプリケーション(サンプル)を作ってみたところ、状況は違うのですが同様の問題が発生しました。

     今回、1対多の関係のサンプルということで伝票のWPFアプリを作りました。


    アプリ中のクラスの関係ですが、このサンプルには不似合いですが規模が大きくなったときを考えて以下のように役割を持たせました。

    それで、MainWindowにDataGridを配して、選んだレコードを編集にまわすと上記のSubWindowが開いて編集、という形にしました。

    その部分のコードが、これで、_modelは Managerクラスです(DbContextを使ってDBアクセスします)。

            private void ExecuteEditCommand()
            {
                var slip = _model.NewSlip(Item);
                if (!SubWindowViewModel.ShowDialog(slip)) return;
                Item.SetProperties(slip);
    
                _model.SaveChanges();
            }

    Itemは選択行のSlip(伝票)型で、SlipLinesという名前で明細をObservalCollectionとして持っています。Itemを一旦Slip型の別インスタンスにコピーして、編集後に戻していますが、これは参考にした本のやり方に倣いました(選択中の行に対する変更が反映されるとかなんとか…)。

    SetProperties()は以下のとおりです(_model.NewSlip()の中でも同じものを呼んでいます)。

            public void SetProperties(Slip source)
            {
                this.Id = source.Id;
                this.Name = source.Name;
                this.Date = source.Date;
    
                this.SlipLines.Clear();
                foreach (var s in source.SlipLines)
                {
                    this.SlipLines.Add(s);
                }
            }

    で、ここからが本題なのですが、このサンプルアプリでは、伝票明細の更新(数量を増減したり)や、新規追加は出来ますが、明細行を削除すると

    「操作に失敗しました: 1 つ以上の外部キーのプロパティが NULL 非許容であるため、リレーションシップを変更できませんでした。」

    という前回も見たエラーメッセージが出ます。 Slip型はGekkaさんに教えていただいたように対処しています。

    ここで、slipに格納したりせずに、ItemをそのままSubWindowに渡すとエラーは出ません。疑問なのはなぜslipにコピーしたものを渡すと更新や新規追加は問題ないのに削除だけ失敗するのだろうか? 回避する方法はあるのだろうか?という点です。

    slipとItemは別インスタンス(GetHashCode()が違う)ですが、上のコードのようにslipに一旦コピーしてItemに戻してSaveChanges()をかけても、コンテキストを確認すると、どちらもChangedやUnchangedになっていてDetached(コンテキストの外にある)ではありません。

    まとめると

    ・一旦、別インスタンス(slip)にコピーしてGUIでユーザーの編集後、もと(Item)に戻すと、明細の更新や新規は問題ないのに削除が含まれると失敗する。 

    ・どうしてそうなっているのか分からない。 上記のコードでエラーが出ないような方法はないのだろうか。

    このサンプルに限ればItemをそのままSubWindowに渡して開けば動作するのですが、表示用の明細行(いろんな機能付き)とEntity側の明細行(シンプル)を異なるものにして、それらを相互に組み立てなおすような事例も考えているので(ちょっとわかりにくですが) コピーしたインスタンスが無事保存できるかは肝になりそうな気がしています。

    長くなるのでソースを全部貼っていませんが、必要であれば追加しますのでどうかお教えください。



    • 編集済み 雷持 2015年11月27日 7:53 なぜ解決したいかの記述変更
    2015年11月27日 4:48