如何在 sqlInsertCmd.ExecuteNonQuery 之后执行 SqlDataReader

How do I execute a SqlDataReader after sqlInsertCmd.ExecuteNonQuery

我正在向我的 SQL 服务器数据库中插入一个数据行,然后我想查询数据以从插入的行中获取唯一标识符,但我的 SqlDataReader 返回一个空数据集。我在想可能是交易还没有提交或类似的事情,但我不确定。我没有收到错误。

这是我的代码:

try
{
    strQuery = "INSERT INTO clientnames VALUES(NEWID(),'" + txtACLastName.Text + "','" + txtACFirstName.Text + "'," + 1 + ")";

    using (SqlCommand sqlInsertCmd = new SqlCommand(strQuery, sqlConn))
    {
        intQueryResult = sqlInsertCmd.ExecuteNonQuery();

        if (intQueryResult == 0)
        {
            blnSuccess = false;
            goto InsertClientNamesError;
        }
        else
        {
            blnSuccess = true;
        }

        sqlInsertCmd.Dispose();
    }

    if (blnSuccess)
    {
        strQuery = "select clientID from clientnames where firstname = '" + txtACFirstName.Text + "' and lastname = '" + txtACLastName.Text + "'";

        using (SqlCommand sqlSelectCmd = new SqlCommand(strQuery, sqlConn))
        {
            SqlDataReader sqlDataRead = sqlSelectCmd.ExecuteReader();

            while (sqlDataRead.Read())
            {
                strClientID = sqlDataRead.ToString();
            }

            sqlDataRead.Close();
            sqlSelectCmd.Dispose();
        }
    }
}
catch (Exception exQuery)
{
    System.Windows.MessageBox.Show("InsertClientNames: Error, " + exQuery.Message + ", has occurred.");
}

将以下行添加到插入记录的存储过程

SELECT SCOPE_IDENTITY()

这将 return 最后插入的身份值 table。

并使用 cmd.ExecuteScalar() 而不是 ExecuteNonQuery()

ExecuteScalar() 执行查询,return 是查询 return 结果集中第一行的第一列。忽略其他列或行。 [More info][1]

您没有得到想要的结果,因为可能 SqlConnection 没有明确打开(如果没有完整的代码,很难判断)。但是这个 link 向您展示了如何从 reader 读取 --> https://msdn.microsoft.com/en-us/library/haa3afyz(v=vs.110).aspx

但是我建议你不要这样做。原因是您要往返数据库服务器两次,而只有一次可以为您完成这项工作 IF 您使用的是存储过程。此外,由于您没有对查询进行参数化,因此您将自己暴露于 SQL 注入攻击。

存储过程:

CREATE PROCEDURE dbo.INS_clientnames 
(
   @FirstName varchar(100),
   @LastName  varchar(100),
   @NewID     int out
)
AS
BEGIN
  Declare @Err int
  set  @NewID = NewID() -- Get the New ID and store it in the variable ( @NewID ) that the SP will return back to the caller 

  INSERT INTO clientnames values (@NewID , @FirstName ,  @LastName) 
  SET @Err = @@ERROR

  IF @Error <> 0 -- Check If there was an error
  Begin 
       SET  @NewID  = -1 -- Indicates that there was an error. You could log this into a Log Table with further details like error id and name.
  END 

RETURN
END

执行上述存储过程并获取 NewID 的 C# 代码:

using(SqlConnection conn = new SqlConnection(connectionString ))
{
    using(SqlCommand cmd = new SqlCommand("dbo.INS_clientnames", conn))
    {
         cmd.CommandType = CommandType.StoredProcedure;

         // set up the parameters that the Stored Procedure expects
         cmd.Parameters.Add("@FirstName", SqlDbType.VarChar, 100);
         cmd.Parameters.Add("@LastName" , SqlDbType.VarChar, 100);
         cmd.Parameters.Add("@NewId"    , SqlDbType.Int).Direction = ParameterDirection.Output;

         // set parameter values that your code will send to the SP as parameter values
         cmd.Parameters["@FirstName"].Value = txtACFirstName.Text ;
         cmd.Parameters["@LastName"].Value  = txtACLastName.Text  ;

         // open connection and execute stored procedure
         conn.Open();
         cmd.ExecuteNonQuery();

         // read output value from @NewId
         int NewID = Convert.ToInt32(cmd.Parameters["@NewId"].Value);
    }
}

我看到有两种方法可以做到这一点:

  1. 要么在客户端使用 C# 代码生成新的 GUID 并将其传递到查询中 - 那么您已经知道新的 ID 是什么,所以您无需进行第二次查询即可获得它:
  2. 您在服务器端创建您的 GUID,然后 return 使用查询中的 OUTPUT 子句将其发送给调用者

方法 #1:

// define connection string and query
string connStr = "--your connection string here--";
string query = "INSERT INTO dbo.Clients(ClientID, FirstName, LastName) VALUES(@ID, @First, @Last);";

using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(query, conn))
{
    // create the GUID in C# - this is the ID - no need to go get it again - this *IS* the id
    Guid id = Guid.NewGuid();

    // set the parameters
    cmd.Parameters.Add("@ID", SqlDbType.UniqueIdentifier).Value = id;
    cmd.Parameters.Add("@First", SqlDbType.VarChar, 50).Value = "Peter";
    cmd.Parameters.Add("@Last", SqlDbType.VarChar, 50).Value = "Miller";

    // open connection, execute query, close connection
    conn.Open();
    cmd.ExecuteNonQuery();
    conn.Close();
}

方法 #2:

// define connection string and query
string connStr = "--your connection string here--";

// query has an "OUTPUT" clause to return a newly inserted piece of data
// back to the caller, just as if a SELECT had been issued
string query = "INSERT INTO dbo.Clients(ClientID, FirstName, LastName) OUTPUT Inserted.ClientID VALUES(NEWID(), @First, @Last);";

using (SqlConnection conn = new SqlConnection(connStr))
using (SqlCommand cmd = new SqlCommand(query, conn))
{
    // set the parameters - note: you do *NOT* send in a GUID value - the NEWID() will create one automatically, on the server
    cmd.Parameters.Add("@First", SqlDbType.VarChar, 50).Value = "Frank";
    cmd.Parameters.Add("@Last", SqlDbType.VarChar, 50).Value = "Brown";

    // open connection
    conn.Open();

    // execute query and get back one row, one column - the value in the "OUTPUT" clause
    object output = cmd.ExecuteScalar();

    Guid newId;

    if (Guid.TryParse(output.ToString(), out newId))
    {
        //
    }

    conn.Close();
}