2012-04-23 18 views
3

私は2つのエンティティRelayConfig間の多対多の関係を次のようしているStandardContact多対多の関係を更新するエンティティフレームワーク - POCO

エンティティ:今

public class RelayConfig : EntityBase, IDataErrorInfo { 
    ... 
    //Associations 
    public virtual ICollection<StandardContact> StandardContacts { get; set; } 
} 


public class StandardContact :EntityBase, IDataErrorInfo { 
    ... 
    //Associations 
    public virtual ICollection<RelayConfig> RelayConfigs { get; set; } 
} 

I RelayConfigとStandardContactとの関係を更新しようとしています。 RelayConfigを更新するコードは次のとおりです。

public class RelayConfigRepository : GenericRepository<RelayConfig> { 
    .... 

    public void Update(RelayConfig relayConfig, List<StandardContact> addedContacts, List<StandardContact> deletedContacts) { 
     context.RelayConfigs.Add(relayConfig); 
     if (relayConfig.Id > 0) { 
      context.Entry(relayConfig).State = EntityState.Modified; 
     } 

     addedContacts.ForEach(ad => relayConfig.StandardContacts.Add(ad)); 

     foreach (StandardContact standardContact in relayConfig.StandardContacts) { 
      if (standardContact.Id > 0) { 
       context.Entry(standardContact).State = EntityState.Modified; 
      } 
     } 

     relayConfig.StandardContacts.ToList().ForEach(s => { 
      if (deletedContacts.Any(ds => ds.Id == s.Id)) { 
       context.Entry(s).State = EntityState.Deleted; 
      } 
     }); 
    } 
    ... 
} 

私がアップデートを実行すると、例外が発生します。その内部例外は次のとおりです。

InnerException: System.Data.SqlClient.SqlException 
     Message=Violation of PRIMARY KEY constraint 'PK__Standard__EE33D91D1A14E395'. Cannot insert duplicate key in object 'dbo.StandardContactRelayConfigs'. 

dbo.StandardContactRelayConfigsは、RelayConfigとStandardContactをリンクするリンクテーブルです。ご覧のように、Id> 0の場合(Updateメソッドの最後に削除されたレコードを除く)、Updateコードはすべてのエンティティを変更された状態に変更します。

エンティティ・フレームワークがリンクされた表に行を挿入しようとしているのに、上記の例外が発生して失敗している理由を理解できません。私はすでに、既存のRelayConfig.StandardContactsエンティティのEntityStateをModifiedに変更します。

要するに、上記の例外を貼り付ける理由は何ですか?

について、 Nirvan。

編集: (addedContactsとdeletedContacts)上記の方法を更新するためのパラメータが既にID> 0

EDIT2を持つエンティティ存在している:私は新鮮挿入するためのコードを削除し、あなたの提案を1として( をデータベースに存在しない)レコードを更新メソッドから取得します。だから私の更新メソッドは、既存のStandardContactレコードをRelayConfigコレクションに追加するだけです。しかし、私はまだコードを正しく動作させることができません。最初はここに私が使用しているコードがあります

public void Update(RelayConfig relayConfig, List<StandardContact> addedContacts, List<StandardContact> deletedContacts) { 
     context.RelayConfigs.Add(relayConfig); 

     if (relayConfig.Id > 0) { 
      context.Entry(relayConfig).State = EntityState.Modified; 
     } 


     addedContacts.ForEach(contact => { 
      context.StandardContacts.Attach(contact); 
      relayConfig.StandardContacts.Add(contact); 
      objectContext.ObjectStateManager. 
       ChangeRelationshipState(relayConfig, contact, rs => rs.StandardContacts, EntityState.Added); 
     }); 
    } 

今のところ私は追加されたレコードに集中しています。上記のコードは、StandardContact(contact変数)が他の既存のRelayConfigオブジェクトとの関係を持たない場合に有効です。この場合、RelayConfig.StandardContactsコレクションに追加された各連絡先のジャンクションテーブルに新しいエントリが作成されます。しかし、StandardContact(連絡先変数)がすでに他のRelayConfigオブジェクトと関係していると、状況が悪くなります(予測できない動作)。この場合、StandardContactがRelayConfig.StandardContactsコレクションに追加されると、StandardContactもデータベースに追加され、重複エントリが作成されます。それだけでなく、新しいRelayConfigオブジェクトも作成されます(どこからわかっていないか)、RelayConfigsテーブルに挿入されます。エンティティフレームワークが多対多の関係で動作する方法を理解することは本当にありません。

@Ladislav、多対多リレーションシップの更新(分離されたエンティティ用)で動作するサンプルコードがある場合は、同じことを表示してください。

に関して、 Nirvan

EDIT3(ソリューション):

は結局、私は完全に異なるアプローチを使用して終了。ここで更新

public void Update(RelayConfig relayConfig, List<StandardContact> exposedContacts) { 

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

     relayConfig.StandardContacts.Clear(); 
     exposedContacts.ForEach(exposedContact => { 
      StandardContact exposedContactEntity = null; 
      exposedContactEntity = context.StandardContacts.SingleOrDefault(sc => sc.Id == exposedContact.Id); 
      if (exposedContactEntity != null) { 
       relayConfig.StandardContacts.Add(exposedContactEntity); 
      } 
     }); 
    } 

に関して、 Nirvanためのコードです。

答えて

10

多対多の関係には独自の状態があるという問題があります。あなたがこの呼び出すのであれば:

addedContacts.ForEach(ad => relayConfig.StandardContacts.Add(ad)); 

をすべて追加の連絡先は、多くの関係に多くのためのあなたの接合テーブルに挿入される新しい関係あるEFを伝えるが、これを呼び出す:

foreach (StandardContact standardContact in relayConfig.StandardContacts) { 
    if (standardContact.Id > 0) { 
     context.Entry(standardContact).State = EntityState.Modified; 
    } 
} 

して状態を変更します関係の状態ではなく連絡先エンティティの新しい状態として追跡されます(btw。変更はできませんが、追加、削除、または変更されません)。したがって、すべての連絡先の変更関係をジャンクション・テーブルに追加し、データベース内に同じリレーションがすでに存在する場合は、ジャンクション・テーブルにはPKが2つしかないFKも含まれているため、同じ関係= PK違反が発生します)。

ます。また、使用して関係の状態を設定する必要があります。

var objectContext = ((IObjectContextAdapter)context).ObjectContext; 
objectContext.ObjectStateManager.ChangeRelatioshipState(...); 

しかし、ここでは、問題が来る:あなただけの既存または新規頼る設定で新しい関係を作成しても連絡既存の連絡先との間で異なっていなければなりません完全に新しいです - 私は完全に新しい連絡先を別々に扱うことをお勧めします。そうでなければあなたのコードは非常に複雑になります。

+0

お返事ありがとうございます。しかし、私はまだ疑いがあります。 addedRecordsまたはdeletedRecordsがないと仮定します。 RelayConfigに2つのStandardContactレコードがあり、これらの2つのStandardContactレコードに変更を永続化したい場合、EntityStateを変更するだけでなく、これらの2つのStandardContactのRelationshipStateを変更する必要がありますか?私は関係の多方面をどのように更新するのですか(今は追加されたレコードと削除されたレコードを無視する)。 – Jatin

+0

realayConfigを追加する場合は、関係状態を変更しないで変更する必要があります。あなたがAttay realayConfigだけであれば、それらの関係で何もする必要はありませんが、新しい関係を追加したい場合には、添付すると別の問題が発生する可能性があります。 –

+0

Edit2と記された編集をご覧ください。 – Jatin

関連する問題