2012-02-21 13 views
1

エンティティのいくつかのプロパティのみを変更できる場合、このコードではシナリオがあります。それを保証するために、我々はこのようなコードがあります。新しいインスタンスを返すようにEntity Frameworkを強制する

public void SaveCustomer(Customer customer) 
{ 
    var originalCustomer = dbContext.GetCustomerById(customer.Id); 

    if (customer.Name != originalCustomer.Name) 
    { 
     throw new Exception("Customer name may not be changed."); 
    } 

    originalCustomer.Address = customer.Address; 
    originalCustomer.City = customer.City; 

    dbContext.SaveChanges(); 
} 

をこのコードの問題はdbContext.GetCustomerByIdへの呼び出しは、常に私にCustomerクラスの新しいインスタンスを与えないということです。顧客が既にデータベースからフェッチされている場合、Entity Frameworkはインスタンスをメモリに保持し、後続のすべての呼び出しでインスタンスを返します。

これは実際の問題につながります。customeroriginalCustomerは同じインスタンスを参照することがあります。その場合、customer.NameoriginalCustomer.Nameと等しくなり、データベースと異なるかどうかを検出することはできません。

アイデンティティマップの設計パターンのため、ほとんどの他のORMでも同じ問題が発生していると思います。

これはどのように解決できますか?私は何とかEFに常に顧客クラスの新しいインスタンスを与えるように強制できますか?

代わりにコードをリファクタリングする必要がありますか?誰もがこのシナリオの良いデザインパターンを知っていますか?

+0

?また、あなたの文脈の生涯は何ですか? – ken2k

+0

ああ、申し訳ありません。 GetCustomerByIdは、DbSet .Find()のラッパーメソッドです。有効期間はHTTP要求ごとです。 – jhu

+0

'Name'が変更されないようにするには、上位層のコードが' Customer'エンティティ(= 'Name'が読み込み専用になる新しいクラスを作成する)で動作することを許可しないでください。 –

答えて

1

コンテキストからエンティティを切り離すことによって試すことができます。これにより、コンテキストへのすべての参照(およびidentitymapの動作)が削除されます。だから、 、あなたの方法に顧客を渡す前に、あなたはそれを切り離すことができます。

yourContext.Detach(customer); 
`GetCustomerById`から来たん
+1

これは技術的に正解です。データベースから新しいインスタンスを取得する場合は、先にコンテキストから前のインスタンスを切り離す必要があります。 –

関連する問題