我有一个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思维模式。
答案 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。