2012-11-15 18 views
8

と仮定I持ってEntity Frameworkのコードファーストセットアップで、次のモデルクラス:更新切り離さエンティティ

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テーブルを含み、人とチームの多対多の関係。

ここで、Teamsのコレクションに1つ以上の切断されたTeamオブジェクトが含まれている(プロキシではなく、まだコンテキストに接続されていない)Personオブジェクトがあるとします。 IDが1の人とIDが3でチームはすでにDBに存在していれば、ちょうど例えば、以下によって作成されるようなオブジェクト:

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

このオブジェクトを更新する最良の方法は何ですか、更新後、TeamPersonsテーブルにBobの単一の行が含まれ、Cチームにリンクされます。私は明らかにしようとしました:

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

しかし、チームコレクションはこれで無視されます。私も様々なことを試しましたが、私がここにいるのはまったく何もしていないようです。助けてくれてありがとう。

EDIT:

だから私はそれらを更新して、変更をコミットし、DBから[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や何かを少しでも簡単に使うことができると知っていますが、新しい人物を取得してすべてのプロパティをコピーする必要はなく、元の人物オブジェクトを保存する方法がないと残念です。

答えて

1

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

+0

購入自体を持っている場合、これは動作していないよう知らせませんでした:その人にDBから取り出されたチームを追加しますプロキシではないため、TeamPersonsテーブルは更新されません。仕事はdbからTeamとPersonの両方をフェッチしているので(Personはプロキシですが)、このフェッチされたPersonを更新して、保存されているPersonと一致させる必要があります... – Duncan

+1

読んでいる方が良い)。編集後: 'DbContext.Entry(dbPerson).CurrentValues.SetValues(person)'を使うことができます。 –

+0

ありがとう、それは便利です - 私はCurrentValues.SetValuesについて知りませんでした – Duncan

0

まず、既存のエンティティを選択してから、そのチームをpersonオブジェクトのチームコレクションに追加してみてください。このような

何か:(構文が正確に正しくない可能性があります)

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(); 
} 
+0

ありがとうございます、しかし、私は保存したいオリジナルからこの新しい人を更新する必要があります(私の編集を参照してください) - 私はそこにいると思っていた別の方法。 – Duncan

+0

さて、あなたは切断された人物に多くの変更があると言っていますか? – EkoostikMartin

+0

潜在的に、はい:どのオブジェクトのプロパティが変更されているかわからないときに、切断されたPersonオブジェクトからdbを更新する最良の方法を知りたいと思います。 – Duncan

0

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

0

アタッチメソッドを使用できます。これを試してみてください:

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(); 
} 

私は、このコードをテストし、私はあなたが何か問題

関連する問題