2011-02-25 86 views
3

我們得到了一個存儲新聞訂閱(ID,EmailAddress,MyNewsletter1等)的表格,當我們保存訂閱時,我們首先檢查是否已經爲該電子郵件地址設置了訂閱。如果有,我們更新該記錄,如果沒有我們插入一個新記錄。不知怎的,一個重複的電子郵件地址在那裏偷偷摸摸,我不知道如何。主鍵是ID,所以我們可以將其改爲EmailAddress,但我仍然好奇這是如何發生的。這可能是一個併發問題嗎?這是代碼:創建了重複記錄,但是爲什麼? (linq to sql)

public static void SaveSubscription(NewsletterSubscription subscription) 
{ 
    using (MyDataContext db = new MyDataContext()) 
    { 
     // does this email already have subscriptions? 
     NewsletterSubscription result = db.NewsletterSubscriptions.SingleOrDefault(r => r.Email == subscription.Email); 

     if (result != null) 
     { 
      // update instead of creating new record 
      result.MyNewsletter1 = subscription.MyNewsletter1; 
      result.MyNewsletter2 = subscription.MyNewsletter2; 
      result.MyNewsletter3 = subscription.MyNewsletter3; 
      result.MyNewsletter4 = subscription.MyNewsletter4; 
     } 
     else 
     { 
      // create new subscription record 
      subscription.RegisterDate = DateTime.Now; 
      db.NewsletterSubscriptions.InsertOnSubmit(subscription); 
     } 

     db.SubmitChanges(); 
    } 
} 

感謝,

Annelie

回答

2

聽起來這只是兩個連接進行讀取/插入之間的競爭條件。一個修復可能會創建一個圍繞兩個操作的串行事務:

using (var tran = new TransactionScope()) { 
    using (MyDataContext db = new MyDataContext()) { 
     // ... your existing code here 
    } 
    tran.Complete(); 
} 

這個選擇,所以任何第二個線程做讀取將被阻止,直到交易完成時強制鍵範圍鎖;所以你不會看到兩個SPID看到「沒有行」,然後嘗試插入;取而代之的是第一個SPID將第二次在幾毫秒的時間內完成工作;只有當第一個SPID決定是否插入數據(並且調用Complete或回滾)第二個SPID纔會知道。

此外,請注意,您不需要更改主鍵以使其唯一 - 只需添加一個唯一約束即可。那麼你不必改變任何參考該表。

+0

會做出這些改變,感謝您的幫助! – annelie 2011-02-25 14:15:36

1

的代碼似乎確定,所以我猜併發問題。如果電子郵件只能有一個記錄,我會建議在主鍵上添加/替換。

在這種情況下,如果您嘗試再次插入相同的記錄,SubmitChanges將引發異常。然後,您可以在catch塊內進行測量以更新記錄(或者在適當的情況下丟棄記錄),然後繼續執行。

獲取數據庫以通過提供正確的主鍵來避免重複。

2

正如一些人已經表示這可能是一個併發問題,你應該讓數據庫幫助你避免它。如果你不想改變主鍵,那麼你可以添加一個唯一的約束到你的電子郵件列。