我有一个表'testTable':
[Id] [Name]
0 'something'
1 'something'
2 'something'
3 'something'
Id列不是Identity,而是主键,因此我将值添加为
INSERT INTO testTable VALUES (2, 'something')
我需要C#方法只带[Name]
列,在表中插入此参数并返回[Id]
列的值。
示例:我使用传递的字符串'test'调用方法。结果应该是:
1)在[Id]
= 4和[Name]
='test'的表格中插入行
2)方法返回[Id]
,即4
我已经实现了具有SQL查询的方法,如:
declare @Id int;
set @Id = ISNULL((SELECT MAX(ID) FROM testTable) + 1, 0);
insert into testTable OUTPUT @Id values (@Id, @name);
对于单线程,它工作正常。但是,如果我调用此方法,例如,在
中Parallel.For(0, 10, <lambda with method>);
我抓住了异常
违反PRIMARY KEY约束'ID_PK'。无法插入重复 对象'testTable'中的键
我想我可以使用C#lock
关键字,但如果只能使用SQL查询,那就太棒了。谢谢。
答案 0 :(得分:1)
您应该创建一个标识列,但不能总是控制数据库设计。
当我遇到这种情况时,我使用辅助方法
/// <summary>
/// Execute a non-query with a retry to handle collisions with non-identity keys
/// </summary>
/// <remarks>The command is retried while unique constraint or duplicate key errors occur
/// <note type="caution">To be meaningful the command must try different values on each try
/// e.g. INSERT INTO.. (Key) VALUES (SELECT MAX(Key)+1, ...</note></remarks>
/// <param name="command">Command to execute</param>
/// <param name="retries">Maximum number of retries</param>
/// <returns>Number of rows affected. </returns>
public static int ExecuteNonQueryWithRetry(this SqlCommand command, int retries) {
for (int failCount = 0;;) {
try {
return command.ExecuteNonQuery();
}
catch (SqlException ex) {
const int UniqueConstraintViolation = 2627;
const int DuplicateKey = 2601;
if (++failCount >= retries ||
(ex.Number != UniqueConstraintViolation &&
ex.Number != DuplicateKey))
throw;
}
}
}
辅助方法的用法如下:
var command = new SqlCommand();
command.CommandText = "INSERT INTO testTable ( " +
" ID " +
" ,... " +
" ) " +
" VALUES ( " +
" (SELECT COALESCE(MAX(Id), 0) + 1 " +
" FROM testTable) " +
" ,... " +
" )";
// assign parameter, connection etc
const int MaxRetries = 2;
if (command.ExecuteNonQueryWithRetry(MaxRetries) != 1)
throw new Exception("Oops");