2011-07-05 1 views
2

EFに関して見つかった類似の投稿をすべて読んでいますが、解決策を見つけることができません。EF SaveChanges()が例外をスローする 'プロパティの現在の値がnullの場合にのみEntityKeyプロパティを設定できます'

私はEFの新機能で、作業に役立つ情報をいくつか読んできましたが、何か不足していると思います。

シナリオは、このようなものです:

私は、ユーザーがASP.NET Webページでアカウントを作成することができるようにしたいです。だから私は 'アカウント'というテーブルを持っています。ユーザーはサイトの条件条項に同意しなければなりません。これはFutereで更新される可能性があります。したがって、アカウントと1対多の関係を持つ「ConditionTerms」という表があります(多くのアカウントには固有の条件項があります)。

アカウントのデータから特定の個人ユーザーデータを分離したいので、私は「Persons」というテーブルも作成しました。私は、関係者が多くのアカウントを持つように関係船を設定しました。

今、データベースにアカウントを保存する場合、データベースで使用可能な最後の条件を取得し、アカウントエンティティに追加します。その後、SaveChanges()を介してデータを保存しようとすると、投稿のタイトルに例外が表示されます。問題は、すべてのエンティティが新しい場合、関連付けが作成されると、すべてのアイテムのEntityStateが「デタッチ」され、機能しますが、既存のconditionTermをデータベースから取得してaccount.ConditionTermに追加するとアカウントは状態を「追加済み」に変更し、例外をスローします。

これは、すべてのエンティティツリーが既にコンテキストによって追加されているとみなされ、既に追加されているためAddObject()メソッドなしでSaveChanges()を呼び出す必要があることを意味します。私はこれを試した後、例外もなくコードも終了しますが、データベース(SQL Server 2008 Express)をチェックすると、アカウントはまったく追加されません。

これは私がしようとしているコードがあると私はそれが動作するはずだと思うけど、それは私が何かが欠けてることは明らかです:

[TestMethod] 
public void TestCreateNewAccount() 
{ 
    try 
    { 
     AccountRepository accountRepository = new AccountRepository(); 

     Account account = new Account() 
     { 
      Username = "TestUsername", 
      Password = "TestPassword", 
      Email = "TestEmail", 
      Nickname = "TestNickName", 
      Quote = "Test Quote", 
      AgreedToTermsDate = DateTime.Now, 
      CreationDate = DateTime.Now, 
      LastUpdateTime = DateTime.Now 
     }; 

     // This works (all new entities!) 
     //ConditionTerm conditionTerm = new ConditionTerm() 
     //{ 
     // Text = "This is some test condition term.", 
     // CreationDate = DateTime.Now, 
     // LastUpdateTime = DateTime.Now 
     //}; 

     //This does not work (attaching an existing entity to a new one) 
     ConditionTerm conditionTerm = new ConditionTermsRepository().GetCurrentTerm(); 

     Person person = new Person() 
     { 
      FirstName = "TestName", 
      Surname = "TestSurname", 
      CreationDate = DateTime.Now, 
      LastUpdateTime = DateTime.Now 
     }; 

     account.ConditionTerm = conditionTerm; 
     account.Person = person; 

     using (ImproveEntities entities = Connection.GetModel()) 
     { 
      if (account.ID > 0) 
      { 
       Account newAccount = new Account(); 
       newAccount.ID = account.ID; 
       entities.Accounts.Attach(newAccount); 
       entities.Accounts.ApplyCurrentValues(account); 
      } 

      else 
      { 
       entities.Accounts.AddObject(account); 
       entities.SaveChanges(); 
      } 
     } 
    } 

    catch (Exception) 
    { 
    } 
} 

すべてのヘルプは非常にapreciatedされるだろう!

EDIT:これはGetCurrentTerm()メソッドです:

public ConditionTerm GetCurrentTerm() 
    { 
     using (ImproveEntities entities = Connection.GetModel()) 
     { 
      ConditionTerm conditionTerm = (from ct in entities.ConditionTerms 
              orderby ct.CreationDate descending 
              select ct).FirstOrDefault(); 
      return conditionTerm; 
     } 
    } 
+0

?私は 'GetCurrentTerm'がそれ自身のコンテキストを使用し、' using'が第2のコンテキストを作成すると思います。 'GetCurrentTerm'のコンテキストが破棄されているか、または' conditionTerm'がこのコンテキストに引き続き接続されていますか? 'GetCurrentTerm'のコードを表示できますか?そして、私たちは 'else'ブロックについてのみ話していますか?あなたのAccountのIDが何らかの値に設定されていない限り、 'account.ID'がいつあなたのコードで0よりも大きいことがわかりません。 – Slauma

+0

こんにちはスラマ! GetCurrentTerm()メソッドのコードを追加しました。私はどこかで、使用節でコンテキストを使用するのが一般的なベストプラクティスであると読むので、常に最後に配置されるようにします。そこに何か問題はありますか? elseメソッドはテストメソッドではあまり意味がありませんが、SaveAccount()メソッドで新しいアカウントや既に存在するものを渡すことができます(私はそれを更新できます)。 –

+0

申し訳ありませんが、私は 'if'ブロックを意味しました。私が新しいアカウントを追加しようとしている瞬間に、私はアップデートでさらに詳しく説明します。 –

答えて

4

私が正しく理解していれば、あなたがデータベースに新しいユーザーを持つ新しいアカウントを沿って挿入します。しかし、新しいConditionTermを作成する代わりに、既存のConditionTermをアカウントに割り当ててください。

問題は、新しいアカウントの保存に使用するコンテキストとは別のコンテキスト(GetCurrentTerm)の既存のConditionTermをフェッチすることです。この第二のコンテキストがConditionTermについて何も知らないので、あなたは明示的にEF第二のコンテキストにそれを取り付けることによって、このconditionTermがすでに存在していることを伝える必要があります:右、あなたがそこに2つのコンテキストで作業している

// ... 
    using (ImproveEntities entities = Connection.GetModel()) 
    { 
     entities.ConditionTerms.Attach(conditionTerm); 

     account.ConditionTerm = conditionTerm; 
     account.Person = person; 

     entities.Accounts.AddObject(account); 
     entities.SaveChanges(); 
    } 
    // ... 
+0

ありがとうございます!あなたのソリューションは魅力的な働きをして、とても良い説明です。あなたは救われたかもしれない。さて、EFの仕組みをもう少し理解していますが、ちょっと奇妙なことがあります(シングルトンのようなコンテキストの動作はできませんでしたか?)。 –

+0

私はあなたの答えを役に立つものとしてマークしたいと思います。私は十分な評判を持っていない、私は申し訳ありません! –

+0

@Albert C .:レポに単一のコンテキストを注入するという古い答えが見つかりました:http://stackoverflow.com/questions/5823115/adding-user-to-a-role-inserts-a-duplicate-user-ユーザ向けテーブル/ 5823230#5823230。シングルトンはあなたの特定の状況で動作します。しかし、一般的に、アプリケーションライフタイム全体に存在するシングルトンコンテキストで作業することは純粋な悪として広く考えられています。特に、オブジェクトが 'SaveChanges'の後のコンテキストから消えないため、多くの問題を引き起こす可能性があります。それを処分します(しかしそれ以上シングルトンはありません)。 – Slauma

関連する問題