【问题标题】:SQL - Get next value of isIdentity columnSQL - 获取 isIdentity 列的下一个值
【发布时间】:2012-03-21 13:11:14
【问题描述】:

我正在开发一个更新内容管理系统,管理员可以在其中添加、编辑和删除更新。

在管理员添加更新的表单中,我想创建一个文本框,用于显示数据库中名为“Update_ID”的 isIdentity 列的下一个值。我不能只从数据库中检索最后一行并向其添加 1,因为如果管理员删除数据库中的最后一条记录,则文本框中的值将不会反映下一行的真实“Update_ID”。

请问这个怎么解决?有没有办法获取数据库中下一个 isIdentity 列的实际值?谢谢:)

【问题讨论】:

  • 为什么你需要显示该值,因为它可能在一毫秒后就不同了?只有在通过SCOPE_IDENTITY(SQL-Server) 创建和检索它之后才能信任它。
  • @Tim Schmelter 我需要在“添加更新”表单上显示值。但是,当从同一表单添加图像时,我需要在 SQL 语句中使用此值,这才是真正的问题发生的时候。
  • @Steve 我使用的是 SQL Server 2008。我的问题是,如果管理员删除标识为 23 的最后一行,然后添加更新,则文本框中的值将显示 23,数字 23 是从同一表单添加图像时使用,即使要插入的行的实际值为 24。
  • 因此,新记录在“Updates”表中的“Update_ID”为 24,而新图像在“Images”表中的“Update_ID”为 23。结果,我失去了图像和更新之间的关系。此外,这些图像现在可能与另一个更新相关联,与它们无关。
  • 看看my answer here,它显示了如何检索新的id。然后,您可以将此 id 用作图像表的外键。或者您可以将两者包装在一个存储过程(和事务)中。

标签: c# asp.net sql


【解决方案1】:

如果您有兴趣做这样的事情,唯一有效的方法是实际插入空白行并将该行返回给用户进行编辑,因为您无法知道下一个 ID 是什么不为插入锁定表,这可能不是您想要做的。

更有效的解决方案可能是在用户最初输入数据时不填写 Update_ID 字段,然后通过选择 SCOPE_IDENTITY 或从插入语句返回值来告知他们您刚刚创建的 ID。

编辑: 对于您想要做的事情(如果您选择升级到 SQL Server 2012),一种可能的替代方法是使用新的Sequences 功能。不过,我以前从未使用过它。

【讨论】:

  • 谢谢 :) 问题是从同一表单插入图像时使用了相同的“Update_ID”编号。请参阅我的问题下的最后两个 cmets。
  • 我发现 cmets 非常混乱。我不确定你为什么要玩弄 ID——从这些 cmets 很难理解系统的设计应该是什么。无论哪种方式,知道下一个 IDENTITY 值(可能是 IDENT_CURRENT)并使用该知识将关联的数据标记到尚未发生的插入是灾难的根源。
  • @Matthew:查看编辑。我想知道您是否可以访问 SQL 2012? ;-)
【解决方案2】:

您可以在会话或表范围内获取最后插入的标识值,这里有一些阅读:

但您必须记住,这些值会随着每次向表中插入而发生变化,因此您不能信任它们。最好的方法是不要在前面显示这个值。在相关资源的情况下,您可以创建一个存储过程(或只是一个内联 T-SQL 块),它将插入到主表中,检索 SCOPE_IDENTITY,然后使用检索到的值对子表进行插入。

编辑

只是我上面描述的一个例子(使用 ADO.NET):

using (SqlConnection connection = new SqlConnection(_connectionString))
{
    connection.Open();

    SqlTransaction transaction = connection.BeginTransaction();

    int insertedIdentity;
    using (SqlCommand command = new SqlCommand("INSERT INTO TableNames(ColumnsList) VALUES(@ValuesList) SELECT @InsertedIdentity = SCOPE_IDENTITY()", connection, transaction))
    {
        command.CommandType = CommandType.Text;
        //Add any parameters required by INSERT here, then add parameter for SCOPE_IDENTITY
        ...
        command.Parameters.Add(new SqlParameter("@InsertedIdentity", SqlDbType.Decimal) { Direction = ParameterDirection.Output });
        command.ExecuteNonQuery();
        insertedIdentity = Convert.ToInt32(command.Parameters["@InsertedIdentity"].Value);
    }

    //Now you can make all the child inserts using insertedIdentity and transaction
    ...

    transaction.Commit();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-02
    • 2012-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多