MVC アプリケーションの MS Dynamics にユーザーを挿入する次のコードがあるとします。
public bool CreateContact(string email)
{
if (crm.contacts.Count(x => x.Email == email) > 0)
return false; //Email already exist in the Crm. Skip
var contact = new contact {Email = email};
crm.AddTocontacts(contact);
crm.SaveChanges();
return true;
}
Dynamics で重大なパフォーマンスの問題が発生した最近まで、ユーザーが同じ電子メール アドレスで登録するのを防ぐのに非常に効果的でした。
どうやら、ユーザーは大幅な遅延を受けており、このコードを実行するボタンを 3 回クリックすることがよくあります。
問題は、最初のリクエストで .SaveChanges() が終了する前に、異なる Http リクエストで .Count() が同時に起動していることです。その結果、同じ電子メール アドレスを持つ連絡先が表示されます。
すでにクライアント側から修正を追加しましたが、これがサーバー側でも実行できるかどうかを確認したいと思います。
このスレッドセーフにするための良い戦略は何でしょうか?
編集:
多くの人がここで提案しているように、CRM に制約を追加することが最善の解決策ですが、この問題が発見されるずっと前に CRM に重複が既に存在しているため、現時点ではその解決策を実装できません。どうやら、CRM と通信するアプリケーションが複数あるようです。
ロックとスレッド化の経験がほとんどないため、最終的に次のことを行いました。
internal static class ContactLock
{
internal static readonly object Locker = new object();
}
public bool CreateContact(string email)
{
lock(ContactLock.Locker)
{
if (crm.contacts.Any(x => x.Email == email))
return false; //Email already exist in the Crm. Skip
var contact = new contact {Email = email};
crm.AddTocontacts(contact);
crm.SaveChanges();
return true;
}
}
単体テストに合格し、問題なく動作しているようです。