2011-02-25 80 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

正如一些人已经表示这可能是一个并发问题,你应该让数据库帮助你避免它。如果你不想改变主键,那么你可以添加一个唯一的约束到你的电子邮件列。