【问题标题】:SCOPE_IDENTITY is not working in asp.net?SCOPE_IDENTITY 在 asp.net 中不起作用?
【发布时间】:2010-01-28 16:45:27
【问题描述】:

我正在尝试插入一条记录并通过一个一个执行两个查询来获取其新生成的ID,但不知道为什么它给我以下错误。

Object cannot be cast from DBNull to other types

我的代码如下:(我不想使用sql存储过程)

SqlParameter sqlParam;
    int lastInsertedVideoId = 0;

    using (SqlConnection Conn = new SqlConnection(ObjUtils._ConnString))
    {
        Conn.Open();
        using (SqlCommand sqlCmd = Conn.CreateCommand())
        {
            string sqlInsertValues = "@Name,@Slug";
            string sqlColumnNames = "[Name],[Slug]";
            string sqlQuery = "INSERT INTO videos(" + sqlColumnNames + ") VALUES(" + sqlInsertValues + ");";
            sqlCmd.CommandText = sqlQuery;
            sqlCmd.CommandType = CommandType.Text;

            sqlParam = sqlCmd.Parameters.Add("@Name", SqlDbType.VarChar);
            sqlParam.Value = txtName.Text.Trim();

            sqlParam = sqlCmd.Parameters.Add("@Slug", SqlDbType.VarChar);
            sqlParam.Value = txtSlug.Text.Trim();


            sqlCmd.ExecuteNonQuery();

            //getting last inserted video id
            sqlCmd.CommandText = "SELECT SCOPE_IDENTITY() AS [lastInsertedVideoId]";
            using (SqlDataReader sqlDr = sqlCmd.ExecuteReader())
            {
                sqlDr.Read();
                lastInsertedVideoId = Convert.ToInt32(sqlDr["lastInsertedVideoId"]);
            }
        }
    }

    //tags insertion into tag table
    if (txtTags.Text.Trim().Length > 0 && lastInsertedVideoId > 0)
    {
        string sqlBulkTagInsert = "";
        string[] tags = txtTags.Text.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
        foreach (string tag in tags)
        {
            sqlBulkTagInsert += "INSERT INTO tags(VideoId, Tag) VALUES(" + lastInsertedVideoId + ", " + tag.Trim().ToLowerInvariant()+ "); ";
        }

        using (SqlConnection Conn = new SqlConnection(ObjUtils._ConnString))
        {
            Conn.Open();
            using (SqlCommand sqlCmd = Conn.CreateCommand())
            {
                string sqlQuery = sqlBulkTagInsert;
                sqlCmd.CommandText = sqlQuery;
                sqlCmd.CommandType = CommandType.Text;

                sqlCmd.ExecuteNonQuery();
            }
        }
    }

如果可能,请检查上述代码是否编码良好,或者我们可以对其进行更多优化以提高性能?

谢谢

【问题讨论】:

标签: c# asp.net sql identity


【解决方案1】:

对 SCOPE_IDENTITY() 的调用不会被视为与您正在执行的 INSERT 命令在同一“范围”内。

基本上,你需要做的就是换行:

string sqlQuery = "INSERT INTO videos(" + sqlColumnNames + ") VALUES(" + sqlInsertValues + ");";

到:

string sqlQuery = "INSERT INTO videos(" + sqlColumnNames + ") VALUES(" + sqlInsertValues + "); SELECT SCOPE_IDENTITY() AS [lastInsertedVideoId]";

然后调用

int lastVideoInsertedId = Convert.ToInt32(sqlCmd.ExecuteScalar());

而不是 .ExecuteNonQuery 和“//获取最后插入的视频 ID”注释之后的代码块。

【讨论】:

  • 我不知道为什么,但是当我像 int lastVideoInsertedId = (int)sqlCmd.ExecuteScalar(); 那样做时它给了我 System.InvalidCastException: Specified cast is not valid. 错误
  • 知道了:我像int lastVideoInsertedId = Convert.ToInt32(sqlCmd.ExecuteScalar()); 一样尝试过它,它的工作原理。不知道是什么原因,知道的请解释一下。还请编辑您的答案并包含此转换方法。谢谢
  • 刚刚编写了一个快速测试程序,看起来(至少从我针对 Sql Server 2008 运行的人为示例中)底层数据类型是 System.Decimal,而不是我预期的 Int32,如何很奇怪!
  • @Prashant 将参数添加到 sqlCommand 会在 ExecuteScalar() 运行后关闭作用域,因此 ExecuteNonQuery() 被放置到不同的作用域中。
【解决方案2】:

SCOPE_IDENTITY() 应从第一个命令(SELECTRETURNOUT)中提取并传递到下一个命令。我的意思是 SELECT_IDENTITY() 应该在 first 命令的末尾。在 SQL 2008 中,作为INSERT 的一部分,有额外的语法可以将值带回,这使得这更简单。

或者更有效:将命令组合成一个以避免往返。

【讨论】:

  • 但是使用sqlCmd.ExecuteNonQuery(); 我们将如何获得变量中的标识值?还有一件事我不想使用 sql 存储过程。
  • 或者,如果您能提供任何示例代码,那就太好了,谢谢。
  • 如果是OUT 参数,那么ExecuteNonQuery 就可以了——如果是RETURN 参数则同上;如果是SELECT,则使用ExecuteReaderExecuteScalar。请注意,OUT/RETURN略微SELECT 更有效,但不是很多。
猜你喜欢
  • 2019-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-10
  • 2016-07-03
  • 2014-04-25
  • 2017-07-17
  • 2012-04-05
相关资源
最近更新 更多