9

多対多のエンティティを既存のエンティティに追加するたびにEFに変更を保存させることができないため、私は約2日間髪を引っ張っています。

私の構造は単純です:

  • と呼ばれるテーブルPersonがあり、ID(Primary、identity)、およびその他のいくつかの文字列フィールドがあります

  • KeywordID(Primary、identity)と呼ばれる文字列フィールドと呼ばれるテーブルValue

  • およびPersonKeywordRelation、、、PersonIdおよびKeywordIdフィールド

エンティティを生成すると(データベースを最初に)、期待どおりに機能Personする-allgoodのクラスを取得しICollection<Keyword>ます。

Personキーワードのリストを変更して既存のを保存しようとすると、問題が発生します。キーワードではなく、スカラープロパティ(文字列)のみが保存されます!

  • 遅延読み込みを無効にしてみましたが、効果はありません。
  • データベースから個々のキーワードを再度ロードしてみましたが、効果はありませんでした。
  • すべてのキーワードをコンテキストにロードして、EFが変更を検出するのに役立つかどうかを確認しましたが、そうではありませんでした。

この問題を抱えているのは私だけではないと確信しています(実際、同じテーマについて、ここですでにいくつかの質問を見たので、完全に確信していますが、実用的な答えを見つけることができません。 ..)、主に古いバージョンのEFの場合、これは私がさらに別の質問を始めた理由のもう1つの理由です:この問題に対処するものは何も変更されていませんか?

これが、人の更新(および作成)を行う私のコードです。それに応じてEF保存の変更を行う私の試みに気付くでしょう。

    public void SavePersons(IList<Person> persons)
    {
        // Create a EF Context
        using (var ctx = new MyDbEntities())
        {
            foreach (var person in persons)
            {
                // Attach
                ctx.Persons.Attach(person);

                // Insert or update?
                ctx.Entry(person).State = person.Id == 0 ? EntityState.Added : EntityState.Modified;

                // Get current keywords before clearing from entity
                var keywords = new List<Keyword>(person.Keywords);

                // Clear keywords from entity, so we can add fresh ones, hopefully
                // EF will have an easier time handling this..
                person.Keywords.Clear();

                // Add keywords
                keywords.ForEach(kw =>
                {
                    ctx.Keywords.Attach(kw);
                    ctx.Entry(kw).State = EntityState.Modified;
                    person.Keywords.Add(kw);
                });            
            }

            // Save
            ctx.SaveChanges();
        }
    }
4

3 に答える 3

12

最後に..最後に私は休むことができます!私は解決策を見つけました!それはきれいなものではありませんが、それは機能します!

これがコードです-共有は思いやりがあります。

EntityFrameworkを使用するのはこれが最後です。良いよりも多くの痛みと苦痛を引き起こします。

    public void SavePersons(IList<Person> persons)
    {
        // Create a EF Context
        using (var ctx = new MyDbEntities())
        {
            // Iterate
            foreach (var person in persons)
            {
                // Get current keywords
                var keywords = new List<Keyword>(person.Keywords).ToList();

                // Fetch Person from DB (if its not a NEW entry). Must use Include, else it's not working.
                var newPerson = ctx.Persons
                                       .Include("Keywords")
                                       .FirstOrDefault(s => s.Id == person.Id) ?? person;

                // Clear keywords of the object, else EF will INSERT them.. Silly.
                newPerson.Keywords.Clear();

                // Insert or update?
                ctx.Entry(newPerson).State = newPerson.Id == 0 ? EntityState.Added : EntityState.Modified;

                // Apply new scalar values
                if(newPerson.Id != 0)
                {
                    person.Id = newPerson.Id;
                    ctx.Entry(newPerson).CurrentValues.SetValues(person);

                }

                // Iterate through all keywords
                foreach (var kw in ctx.Keywords)
                {
                    // If the current kw exists in OUR list, add it
                    // - if not, remove the relation from the DB.
                    if (keywords.Any(k => k.Id == kw.Id))
                    {
                        //ctx.Entry(kw).State = EntityState.Unchanged;
                        ctx.Keywords.Attach(kw);
                        newPerson.Keywords.Add(kw);
                    }
                    else
                        newPerson.Keywords.Remove(kw);
                }
            }

            // Save
            ctx.SaveChanges();

        }
    }
于 2013-01-31T20:10:18.060 に答える
2

.ToList()を追加してみてください:

var keywords = new List<Keyword>(person.Keywords).ToList();//generate list sepereate from .Keywords

水分補給する前にクリアしたため、キーワードリストにデータが入力されていないのではないかと思います。

于 2013-01-31T17:48:10.267 に答える
1

したがって、以下はテストされていませんが、私のバグ修正した後;)うまくいけばうまくいくはずです。コードの残りの部分がわからないので、入力データのクローンを作成し、オブジェクトを特定の順序でコンテキストにアタッチすることを選択しました。

編集:名前を変更したメソッド

    // get unique list of Keywords from all Persons
    private List<Keyword> getUniqueKeywords(IEnumerable<Person> oxygenThiefs) {
        var result = new List<Keyword>();

        foreach (var thief in oxygenThiefs) {
            foreach (var keyword in thief.Keywords) {
                if (!result.Contains(keyword)) {
                    result.Add(keyword);
                }
            }
        }

        return result;
    }

    // shallow clone of Person
    private Person clonePerson(Person target) {

        return new Person {
            Id = target.Id,
            Name = target.Name,
            ..
            ..

        };
    }

    public void SavePersons(IList<Person> persons) {
        // Create a EF Context
        using (var ctx = new MyDbEntities()) {

            // add all Keywords to the Context so that they are tracked
            foreach (var keyword in getUniqueKeywords(persons)) {
                ctx.Keywords.Attach(keyword);
                // if value of Keyword has actually changed then uncomment line
                // ctx.Entry(keyword).State = EntityState.Modified
            }

            foreach (var person in persons) {

                // hehe
                var shallowPerson = clonePerson(person);

                // Attach Person
                ctx.Persons.Attach(shallowPerson);

                // Establish relationship (however shallow and meaningless)
                foreach (var keyword in person.Keywords) {
                    shallowPerson.Keywords.Add(keyword);
                }

                // Insert or update?
                ctx.Entry(shallowPerson).State = person.Id == 0 ? EntityState.Added : EntityState.Modified;

            }

            // Save
            ctx.SaveChanges();
        }
    }
于 2013-01-31T17:49:37.643 に答える