使用Linq to SQL正确递增值

时间:2008-12-22 08:53:03

标签: c# linq-to-sql auto-increment

我有一个MS SQL表,我没有任何控制权,我需要写入。此表具有不会自动递增的int主键。我不能使用存储过程,我想使用Linq to SQL,因为它使其他处理非常容易。

我目前的解决方案是读取最后一个值,增加它,尝试使用它,如果我收到冲突,再次增加它并重试。

这些方面的东西:

var newEntity = new Log()
{
    ID = dc.Logs.Max(l => l.ID) + 1,
    Note = "Test"       
};

dc.Logs.InsertOnSubmit(newEntity);

const int maxRetries = 10;
int retries = 0;

bool success = false;
while (!success && retries < maxRetries)
{               
    try
    {                                                           
        dc.SubmitChanges();
        success = true;
    }
    catch (SqlException)
    {
        retries++;
        newEntity.ID = dc.Logs.Max(l => l.ID);                  
    }
}           
if (retries >= maxRetries)
{
    throw new Exception("Bummer...");
}

有没有人有更好的解决方案?

编辑:感谢Jon,我简化了最大ID计算。我还处于SQL思维模式。

4 个答案:

答案 0 :(得分:2)

这看起来像是获取最大ID的昂贵方式。你有没有试过

var maxId = dc.Logs.Max(s => s.ID);

?也许它因某些原因不起作用,但我真的希望它确实......

(不可否认,SQL Server可能会对此进行适当优化。)

除此之外,它对我来说看起来很好(很臭,但必然如此) - 但我不是这方面的专家......

答案 1 :(得分:0)

您没有说明您的应用是否是插入表格的唯一应用。如果是,那么我会在app / webapp启动后立即获取最大值,并在每次需要下一个ID时使用Interlocked.Increment(如果可以排除可能的竞争条件,则使用简单添加)。 / p>

答案 2 :(得分:0)

您可以使用TransactionScope类将整个操作放入事务中,如下所示:

using  (TransactionScope scope = new TransactionScope()){
   var maxId = dc.Logs.Max(s => s.ID); 
   var newEntity = new Log(){        
       ID = maxId,        
       Note = "Test"           
   };
   dc.Logs.InsertOnSubmit(newEntity);
   dc.SubmitChanges();
   scope.Complete();
}  

通过将最大ID的检索和新记录的插入放在同一个事务中,您应该能够拔出插入而无需以您的方式重试。

此方法可能遇到的一个问题是事务死锁,尤其是在大量使用表的情况下。测试一下,看看是否需要额外的错误处理。

P.S。我包含了Jon Skeet的代码来获取代码中的最大ID,因为我很确定它能正常工作。 :)

答案 3 :(得分:0)

使id字段自动递增,让服务器处理id生成。

否则,你会遇到问题liggett78说。没有什么能阻止另一个线程在读取和提交此线程的最大ID之间读取相同的id。