【问题标题】:How to insert a record and return the newly created ID using a single SqlCommand?如何使用单个 SqlCommand 插入记录并返回新创建的 ID?
【发布时间】:2008-12-01 12:37:49
【问题描述】:

我正在使用 SqlCommand 对象将记录插入到具有自动生成的主键的表中。如何编写命令文本,以便在使用 ExecuteScalar() 方法时获得新创建的 ID?

【问题讨论】:

  • 如果您使用的是 Guid,请参阅我的回答。

标签: c# sql sql-server


【解决方案1】:
INSERT INTO YourTable(val1, val2, val3 ...) 
VALUES(@val1, @val2, @val3...);
SELECT SCOPE_IDENTITY();

不要忘记每条语句末尾的分号。

【讨论】:

  • 而不是使用 scope_identity(),您可以只使用输出子句 - INSERT INTO YourTable(val1, val2, val3 ...) 输出插入。$identity VALUES(@val1, @val2, @val3...);
  • 不,你不能。如果您的表上有触发器,您将收到此错误:如果该语句包含没有 INTO 子句的 OUTPUT 子句,则 DML 语句的目标表“站点”不能有任何启用的触发器。
【解决方案2】:

将以下行添加到 Sql Query 的末尾...

SELECT SCOPE_IDENTITY()

然后在SqlCommand对象上使用ExecuteScalar方法……

var rowCount = command.ExecuteScalar()

【讨论】:

    【解决方案3】:
    insert into Yourtable()  
    values()  
    SELECT SCOPE_IDENTITY()
    

    我刚刚运行了一个测试,并使用 SQL Server 2005 SP2 和 .Net 3.5 验证了分号是可选的

    【讨论】:

    • 不知道否决票,但 SET NOCOUNT ON 是不需要使其工作的。可能是缺少的分号。
    • 在 ADO 6.0 中,如果您拉回记录集,则不需要计数,因此我可能会这样做;-)。我只是一个运行测试,你不需要分号,你不需要 set nocount
    【解决方案4】:

    将输出参数添加到命令对象,然后将值设置为存储过程中的新 ID。

    存储过程:

    @ID AS INT OUTPUT
    
    [Insert Command]
    
    SET @ID = SCOPE_IDENTITY()
    

    .NET:

    cmd.CommandText = "stored_procedure";
    
    SqlParameter pID = new SqlParameter("ID", DBType.Int32, 4);
    
    pID.Direction = ParameterDirection.Output;
    
    cmd.ExecuteScalar();
    
    int id = Convert.ToInt32(cmd.Parameters["ID"].Value.ToString());
    

    【讨论】:

      【解决方案5】:

      不要使用@@IDENTITY,不管它看起来多么简单。它可能返回不正确的值。

      SELECT SCOPE_IDENTITY()
      

      似乎是显而易见的选择。

      【讨论】:

        【解决方案6】:

        虽然我喜欢Dave Markle's 答案,(我也看到你这样做了,因为你将它标记为你的答案),如果你的数据库上有触发器、审计 CUD 操作并且你的审计表有,那么该方法可能会失败IDENTITY 列。它将返回审计表的标识值,而不是您刚刚插入的表,因为审计表实际上是在之后发生的。

        在这种情况下,可以使用更通用的方法,在这两种情况下都可以使用,而无需考虑任何审计。它有点罗嗦,但你得到了你付出的代价。

        示例:

        @"DECLARE @tmp AS TABLE ( id int )
                            INSERT INTO case
                            (
                                caseID,
                                partID,
                                serialNumber,
                                hardware,
                                software,
                                firmware
                            )
                            OUTPUT Inserted.ID into @tmp
                            VALUES
                            (
                                @caseID,
                                @partItemID,
                                @serialNumber,
                                @hardware,
                                @software,
                                @firmware
                            )
                        Select ID from @tmp" )
        

        【讨论】:

        • 如果有触发器,Scope_identity 不会失败,@@identity 会失败。
        • @Russ 在处理由 SyncFramework 触发器引起的错误时,您的回答对我有帮助 - 如果语句包含不带INTO 子句。我正在为我的 PK 使用 GUID,并且没有 IDENTITY 列。谢谢!
        【解决方案7】:

        在插入 stmt 后立即使用

        SELECT CAST(scope_identity() AS bigint) ---- incase you have a return result as int64
        

        这将返回创建的 id/identity 列。

        【讨论】:

          【解决方案8】:

          如果您的 id 是 Guid,那么我发现这个解决方案是最好的:

          INSERT INTO YourTable (val1, val2, val3) 
          OUTPUT inserted.id 
          VALUES (@val1, @val2, @val3)
          

          感谢@Scott Ivey

          完整演示:

              internal static Guid InsertNote(Note note)
              {
                      Guid id;
          
                      using (
                          var connection =
                              new SqlConnection(ConfigurationManager.ConnectionStrings["dbconn"].ConnectionString))
                      {
                          connection.Open();
                          using (
                              var command =
                                  new SqlCommand(
                                      "INSERT INTO Notes ([Title],[Text]) " +
                                      "OUTPUT inserted.id " +
                                      $"VALUES ('{title}','{text}');", connection))
                          {
                              command.CommandType = CommandType.Text;
                              var reader = command.ExecuteReader();
                              reader.Read();
                              id = reader.GetGuid(reader.GetOrdinal("id"));
                          }
                          connection.Close();
                      }
          
                      return id;
              }
          

          我建议使用存储过程,但这是为了对我们的存储库进行单元测试。

          【讨论】:

          • 是的!最后,在搜索了将近一个小时后,一个显示如何在 C# 中获取 GUID 的 OUTPUT 值的答案。
          【解决方案9】:

          直接出Whirlpool

          如果您使用的是 MS SQL,您可以在插入后使用“SELECT @@IDENTITY as Value”来生成最后一个 ID

          和:

          @@IDENTITYSCOPE_IDENTITY 返回当前会话中任何表中生成的最后一个标识值。但是,SCOPE_IDENTITY 只返回当前范围内的值; @@IDENTITY 不限于特定范围。

          编辑:正如 cmets 中所指出的,您应该始终使用 SCOPE_IDENTITY,而不是 @@IDENTITY

          【讨论】:

          • 如果你有任何触发器@@Identity 可以返回错误的值
          • 始终使用 SCOPE_IDENTITY。不是@@Identity。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-08-29
          • 1970-01-01
          • 2014-10-19
          • 1970-01-01
          • 2012-10-21
          相关资源
          最近更新 更多