8

Entity Framework Code-First セットアップに次のモデル クラスがあるとします。

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Team> Teams { get; set; }
}

public class Team
{
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Person> People { get; set; }
}

このコードから作成されたデータベースには、人とチームの間の多対多の関係を表す TeamPersons テーブルが含まれています。

ここで、切断された Person オブジェクト (プロキシではなく、まだコンテキストにアタッチされていない) があり、その Teams コレクションに 1 つ以上の切断された Team オブジェクトが含まれており、そのすべてが既にデータベース内にあるチームを表しているとします。たとえば、ID 1 の Person と ID 3 の Team がデータベースに既に存在する場合、次のようなオブジェクトが作成されます。

var person = new Person
{
    Id = 1,
    Name = "Bob",
    Teams = new HashSet<Team>
    {
        new Team { Id = 3, Name = "C Team"}
    }
};

このオブジェクトを更新して、更新後に TeamPersons テーブルに Bob の 1 つの行が含まれ、彼を C Team にリンクする最善の方法は何ですか? 私は明白なことを試しました:

using (var context = new TestContext())
{
    context.Entry(person).State = EntityState.Modified;
    context.SaveChanges();
}

ただし、Teams コレクションはこれによって無視されます。私は他にもさまざまなことを試しましたが、ここで求めていることを正確に行うものは何もないようです. 助けてくれてありがとう。

編集:

したがって、データベースから Person と Team[s] の両方をフェッチし、それらを更新してから変更をコミットできることがわかりました。

using (var context = new TestContext())
{
    var dbPerson = context.People.Find(person.Id);
    dbPerson.Name = person.Name;
    dbPerson.Teams.Clear();
    foreach (var id in person.Teams.Select(x => x.Id))
    {
        var team = context.Teams.Find(id);
        dbPerson.Teams.Add(team);
    }

    context.SaveChanges();
}

ただし、 Person が複雑なエンティティである場合、これは面倒です。Automapper などを使用して物事を少し簡単にできることはわかっていますが、新しいものを取得してすべてのプロパティをコピーするのではなく、元の人物オブジェクトを保存する方法がない場合は残念です...

4

4 に答える 4

2

一般的なアプローチはTeam、データベースからをフェッチし、AddそれをPersonTeamsコレクションにフェッチすることです。設定EntityState.Modifiedはスカラー プロパティにのみ影響し、ナビゲーション プロパティには影響しません。

于 2012-11-15T20:55:48.153 に答える
0

それが EF の失敗です。切断されたシナリオでは非常に非効率的です。更新/削除のためのデータと、更新されたものを再アタッチするためのすべてのデータをロードすると、同じキーを持つエンティティがコンテキストに既に存在している可能性があるため、更新されたエンティティをコンテキストにアタッチすることはできません。その場合、EF は単にスローします。行う必要があるのは、同じキーを持つエンティティが既にコンテキスト内にあり、それに応じて添付または更新されているかどうかを確認することです。多対多の関係の子を持つエンティティを更新するのはさらに悪いことです。削除された子を削除するのは、子のエンティティ セットからですが、参照プロパティからではありません。非常に面倒です。

于 2014-10-30T16:35:41.217 に答える
0

Attach メソッドを使用できます。これを試して:

using (var context = new TestContext())
{
    context.People.Attach(person);

    //i'm not sure if this foreach is necessary, you can try without it to see if it works
    foreach (var team in person.Teams)
    {
        context.Teams.Attach(team);
    }

    context.Entry(person).State = EntityState.Modified;

    context.SaveChanges();
}

このコードはテストしていません。問題があればお知らせください

于 2015-02-25T08:07:18.263 に答える
0

最初に既存のエンティティを選択してから、チームを人物オブジェクトのチーム コレクションに関連付けてみてください。

このようなもの:(構文は正確ではないかもしれません)

using (var context = new TestContext())
{
    var person = context.Persons.Where(f => f.Id == 1).FirstOrDefault();
    var team = context.Teams.Where(f => f.Id == 3).FirstOrDefault();

    person.Teams.Add(team);

    context.Entry(person).State = EntityState.Modified;
    context.SaveChanges();
}
于 2012-11-15T20:56:55.980 に答える