SqlCommand.ExecuteNonQuery example in ASP.NET (C#)
ExecuteNonQuery runs a statement that changes data, or changes the database itself, and returns the number of rows affected. Here it is used in the three situations you will meet most: a single INSERT/UPDATE/DELETE, a stored procedure with an output parameter, and several statements in one transaction.
Insert from a form
<asp:TextBox ID="txtTitle" runat="server" MaxLength="200" />
<asp:TextBox ID="txtDue" runat="server" TextMode="Date" />
<asp:Button ID="btnAdd" runat="server" Text="Add task" OnClick="btnAdd_Click" />
<asp:Label ID="lblResult" runat="server" />
protected void btnAdd_Click(object sender, EventArgs e)
{
if (!DateTime.TryParseExact(txtDue.Text, "yyyy-MM-dd", CultureInfo.InvariantCulture,
DateTimeStyles.None, out DateTime due))
{
lblResult.Text = "Please enter a valid date.";
return;
}
const string sql = "INSERT INTO dbo.Tasks (Title, DueDate, Done) VALUES (@title, @due, 0)";
string cs = ConfigurationManager.ConnectionStrings["Db"].ConnectionString;
using (var con = new SqlConnection(cs))
using (var cmd = new SqlCommand(sql, con))
{
cmd.Parameters.Add("@title", SqlDbType.NVarChar, 200).Value = txtTitle.Text.Trim();
cmd.Parameters.Add("@due", SqlDbType.Date).Value = due;
con.Open();
int rows = cmd.ExecuteNonQuery();
lblResult.Text = rows == 1 ? "Task added." : "Nothing was inserted.";
}
}
A TextMode="Date" box renders an HTML date input, which always posts the value as yyyy-MM-dd whatever the user's display format; parsing it with the invariant culture is therefore reliable.
Update and delete, checking the count
public static bool MarkDone(int taskId, string cs)
{
using (var con = new SqlConnection(cs))
using (var cmd = new SqlCommand("UPDATE dbo.Tasks SET Done = 1 WHERE TaskId = @id AND Done = 0", con))
{
cmd.Parameters.Add("@id", SqlDbType.Int).Value = taskId;
con.Open();
return cmd.ExecuteNonQuery() == 1; // false: unknown id, or already done
}
}
public static int PurgeCompleted(DateTime before, string cs)
{
using (var con = new SqlConnection(cs))
using (var cmd = new SqlCommand("DELETE FROM dbo.Tasks WHERE Done = 1 AND DueDate < @before", con))
{
cmd.Parameters.Add("@before", SqlDbType.Date).Value = before;
con.Open();
return cmd.ExecuteNonQuery(); // number of tasks deleted
}
}
The returned count turns a silent no-op into information. Remember it becomes -1 if the batch sets SET NOCOUNT ON, and that rows changed by triggers are included.
Stored procedure with an output parameter
CREATE PROCEDURE dbo.AddTask
@Title nvarchar(200), @DueDate date, @TaskId int OUTPUT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO dbo.Tasks (Title, DueDate, Done) VALUES (@Title, @DueDate, 0);
SET @TaskId = SCOPE_IDENTITY();
END
using (var con = new SqlConnection(cs))
using (var cmd = new SqlCommand("dbo.AddTask", con) { CommandType = CommandType.StoredProcedure })
{
cmd.Parameters.Add("@Title", SqlDbType.NVarChar, 200).Value = title;
cmd.Parameters.Add("@DueDate", SqlDbType.Date).Value = due;
SqlParameter idParam = cmd.Parameters.Add("@TaskId", SqlDbType.Int);
idParam.Direction = ParameterDirection.Output;
con.Open();
cmd.ExecuteNonQuery(); // returns -1 here because of SET NOCOUNT ON
int newId = (int)idParam.Value; // output values are available after execution
}
Several commands in one transaction
using (var con = new SqlConnection(cs))
{
con.Open();
using (SqlTransaction tx = con.BeginTransaction())
{
try
{
using (var move = new SqlCommand(
"UPDATE dbo.Tasks SET ProjectId = @to WHERE ProjectId = @from", con, tx))
{
move.Parameters.Add("@to", SqlDbType.Int).Value = targetProject;
move.Parameters.Add("@from", SqlDbType.Int).Value = oldProject;
move.ExecuteNonQuery();
}
using (var del = new SqlCommand("DELETE FROM dbo.Projects WHERE ProjectId = @id", con, tx))
{
del.Parameters.Add("@id", SqlDbType.Int).Value = oldProject;
del.ExecuteNonQuery();
}
tx.Commit();
}
catch
{
tx.Rollback();
throw;
}
}
}
Every command that runs on a connection with an open transaction must be given that transaction; otherwise ADO.NET throws "ExecuteNonQuery requires the command to have a transaction…". Either both changes are saved or neither is.
For reading rows or single values instead, see ExecuteReader vs ExecuteNonQuery vs ExecuteScalar.
Official documentation
- Microsoft Learn: SqlCommand.ExecuteNonQuery, SqlConnection.BeginTransaction
- Microsoft Learn: Using parameters with stored procedures (ADO.NET)