Simple SqlCommand.ExecuteNonQuery always returning 1 even when it didn't update database

时间:2015-09-01 21:46:42

标签: c# sql-server ado.net

I am maintaining a Windows service, recently updated/compiled in .Net 4.5, placed on Server 2012, and using the same SQL Server 2008 database it had been running on before the update. We ran into a snag where it is updating the database using a simple SQL statement, which has apparently always worked before the update. Now the update almost always works, but once in (maybe?) a thousand updates it "fools" us and ExecuteNonQuery returns a 1 indicating it updated the row, but really hasn't.

If you want to tell me what is wrong with the code, please go ahead.. What I'm really hoping for is a suggestion on a more "fool" proof way to handle the update. Maybe it would be better to set the connection to use transactions? Maybe it would be far better to use a stored procedure, as well as perform transactions in the stored procedure? How much better/Why?

The code is pretty simple (too simple?):

try
{
    string sql = "UPDATE table SET barcode = '" + newBarcode + "' WHERE pk = '" + reportId + "'"; // no semicolon in the SQL
    SqlCommand command = new SqlCommand(sql, connection); // connection recently opened

    rowsUpdated = command.ExecuteNonQuery();

    if (rowsUpdated != 1)
    {
        connection.Close()
        throw new Exception("...");
    }
    else
    ...
    connection.Close();
}
catch (Exception ex)
... // general exceptions handled
finally
... // make sure connection is closed

I know it is possible (though very unlikely) that outside influences could be nullifying the field after the update. If that is likely the ONLY possibility, please comment.

3 个答案:

答案 0 :(得分:2)

An update that updates the row to the same value is still counted as an affected row.

Compare it with the following:

UPDATE table SET barcode = @x WHERE pk = @id AND barcode <> @x

The explicit guard will skip this row if the update were to "do nothing" and thus it will not be counted as a change if there is no need to make a change.


While one should use placeholders (and using statements) as applicable, neither of these will change the result of the update statement.

答案 1 :(得分:1)

As suggested in other answer too, use parameterised queries as well use the using statement to initialize a connection so you don't have to take the responsibility of it closing it when you are done.

Also use and output parameter along with @@ROWCOUNT function to see if any rows has been updated.

Use the RowsAffected variable to do further processing.

using (SqlConnection conn = new SqlConnection("Connection string here..."))
{
  string sqlcmd = "UPDATE table SET barcode = @newBarcode WHERE pk =  @reportId  SET @RowCount = @@ROWCOUNT;";

    conn.Open();
    SqlCommand cmd = new SqlCommand(sqlcmd, conn);

    cmd.Parameters.Add("@RowCount", SqlDbType.Int).Direction = ParameterDirection.Output;
    cmd.Parameters.Add(new SqlParameter("@newBarcode", newBarcode));
    cmd.Parameters.Add(new SqlParameter("@reportId", reportId));

    rowsUpdated = cmd.ExecuteNonQuery();
    int RowsAffected = Convert.ToInt32(cmd.Parameters["@RowCount"].Value);

   if (RowsAffected == 0)
    {
      throw new Exception("...");
     }
   else
    ......
 }

答案 2 :(得分:-1)

UPDATE查询的ExecuteNonQuery返回值是update语句的where子句匹配的行数,而不是实际更新的行数。

您应该使用连接字符串选项'使用受影响的行'。设置为true时,它将报告已更改的行而不是找到的行。

请参阅https://bugs.mysql.com/bug.php?id=44194