.NET 4.0中使用ADO.NET执行Insert命令无法获取记录ID求助
解决ADO.NET插入后获取主键ID的问题
你的代码获取不到主键ID的核心原因是插入脚本没有将生成的主键赋值给输出参数,同时要保证并发安全,必须使用当前会话作用域内的标识值获取方法,避免拿到其他用户的ID。
方案一:通过输出参数 + SCOPE_IDENTITY() 获取(兼容原有参数设计)
修改插入脚本,在INSERT后添加SET @UserProfileId = SCOPE_IDENTITY(),SCOPE_IDENTITY()会返回当前会话、当前批处理中生成的最后一个主键值,完全避免并发冲突:
private string InsertScript() { string script = "INSERT INTO [dbo].[UserProfile]([UserProfileStatus],[UserProfileAccount],[UserProfileTimeStamp]) " + "VALUES (@UserProfileStatus, @UserProfileAccount, @UserProfileTimeStamp); " + "SET @UserProfileId = SCOPE_IDENTITY();"; return script; }
调整InsertData方法,正确处理输出参数并更新状态:
private bool InsertData() { bool isRecordCreated = false; try { using (SqlCommand cmd = new SqlCommand(InsertScript(), dbConnection)) { cmd.Parameters.Add("@UserProfileStatus", SqlDbType.Int).Value = UserProfiles.UserProfileStatus; cmd.Parameters.Add("@UserProfileAccount", SqlDbType.VarChar).Value = UserProfiles.UserProfileAccount; cmd.Parameters.Add("@UserProfileTimeStamp", SqlDbType.DateTime).Value = UserProfiles.UserProfileTimeStamp; // 定义输出参数,指定Size适配int类型 SqlParameter outputParam = new SqlParameter("@UserProfileId", SqlDbType.Int) { Direction = ParameterDirection.Output, Size = 4 }; cmd.Parameters.Add(outputParam); dbConnection.Open(); int rowsAffected = cmd.ExecuteNonQuery(); // 验证插入成功且参数有值 if (rowsAffected > 0 && outputParam.Value != DBNull.Value) { int newId = Convert.ToInt32(outputParam.Value); isRecordCreated = true; // 可在此处使用newId执行后续操作 } } } catch(Exception ex) { Console.WriteLine(ex.Message); } finally { dbConnection?.Close(); } return isRecordCreated; }
方案二:使用ExecuteScalar直接返回主键(更简洁)
如果不需要保留输出参数,修改脚本通过OUTPUT子句返回主键,用ExecuteScalar直接获取结果:
private string InsertScript() { string script = "INSERT INTO [dbo].[UserProfile]([UserProfileStatus],[UserProfileAccount],[UserProfileTimeStamp]) " + "OUTPUT INSERTED.UserProfileId " + "VALUES (@UserProfileStatus, @UserProfileAccount, @UserProfileTimeStamp);"; return script; }
对应的InsertData方法调整:
private bool InsertData() { bool isRecordCreated = false; try { using (SqlCommand cmd = new SqlCommand(InsertScript(), dbConnection)) { cmd.Parameters.Add("@UserProfileStatus", SqlDbType.Int).Value = UserProfiles.UserProfileStatus; cmd.Parameters.Add("@UserProfileAccount", SqlDbType.VarChar).Value = UserProfiles.UserProfileAccount; cmd.Parameters.Add("@UserProfileTimeStamp", SqlDbType.DateTime).Value = UserProfiles.UserProfileTimeStamp; dbConnection.Open(); object result = cmd.ExecuteScalar(); if (result != null && result != DBNull.Value) { int newId = Convert.ToInt32(result); isRecordCreated = true; // 可在此处使用newId执行后续操作 } } } catch(Exception ex) { Console.WriteLine(ex.Message); } finally { dbConnection?.Close(); } return isRecordCreated; }
关键说明
- 并发安全保障:
SCOPE_IDENTITY()和OUTPUT INSERTED.xxx都是基于当前会话的作用域,只会返回当前插入操作生成的主键,不会被其他用户的并发插入影响。 - 禁用@@IDENTITY:
@@IDENTITY会返回当前会话所有作用域的最后标识值,如果插入后触发触发器生成其他表的标识,会拿到错误的ID,绝对不要使用。
内容的提问来源于stack exchange,提问作者K.Z
相关产品推荐
相关产品推荐

