What's wrong with this simple update request?
Except that I'm insecure ... I don't get an error, but the row is not updated. An integer number of rows is given 1 after the query, indicating that 1 row is affected.
String query = "UPDATE contacts SET contact_name = '" + ContactName.Text.Trim() + "', " +
"contact_phone = '" + Phone.Text.Trim() + "', " +
"contact_fax = '" + Fax.Text.Trim() + "', " +
"contact_direct = '" + Direct.Text.Trim() + "', " +
"company_id = '" + Company.SelectedValue + "', " +
"contact_address1 = '" + Address1.Text.Trim() + "', " +
"contact_address2 = '" + Address2.Text.Trim() + "', " +
"contact_city = '" + City.Text.Trim() + "', " +
"contact_state = '" + State.SelectedValue + "', " +
"contact_zip = '" + Zip.Text.Trim() + "' " +
"WHERE contact_id = '" + contact_id + "'";
String cs = Lib.GetConnectionString(null);
SqlConnection conn = new SqlConnection(cs);
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = query;
cmd.Connection.Open();
int rows = cmd.ExecuteNonQuery();
a source to share
You must use a parameterized query for several reasons:
- exclude the possibility of intrusion into your request
- protecting your database / website from SQL injection
Also, if cmd returns 1, then the row has been updated. You may need to check your expectations ...
String query = @"
UPDATE contacts
SET contact_name = @contact_name, contact_phone = @contact_phone, contact_fax = @contact_fax,
contact_direct = @contact_direct , company_id = @company_id, contact_address1 = @contact_address1,
contact_address2 =@contact_address2, contact_city = @contact_city , contact_state = @contact_state,
contact_zip = @contact_zip
WHERE contact_id = @contact_id";
String cs = Lib.GetConnectionString(null);
using (SqlConnection conn = new SqlConnection(cs))
{
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.Parameters.AddWithValue("@contact_name", ContactName.Text.Trim());
cmd.Parameters.AddWithValue("@contact_phone", Phone.Text.Trim());
cmd.Parameters.AddWithValue("@contact_fax", Fax.Text.Trim());
cmd.Parameters.AddWithValue("@contact_direct", Direct.Text.Trim());
cmd.Parameters.AddWithValue("@company_id", Company.SelectedValue);
cmd.Parameters.AddWithValue("@contact_address1", Address1.Text.Trim());
cmd.Parameters.AddWithValue("@contact_address2", Address2.Text.Trim());
cmd.Parameters.AddWithValue("@contact_city", City.Text.Trim());
cmd.Parameters.AddWithValue("@contact_state", State.SelectedValue);
cmd.Parameters.AddWithValue("@contact_zip", Zip.Text.Trim());
cmd.Parameters.AddWithValue("@contact_id", contact_id);
cmd.CommandText = query;
cmd.Connection.Open();
int rows = cmd.ExecuteNonQuery();
}
}
Now, doesn't it look much cleaner? And when you understand why, it will give you a warm fuzzy feeling and allow you to sleep well at night .; -)
Clarification
Your stated question is "What is wrong with this request." The answer is nothing. Nothing happens in the request.
The problem is your page code that you haven't posted even after 5 people suggested there was nothing wrong with the request.
What I mean by "You might need to check your expectations ..." and "You need to examine the data that goes into the parameters before executing the request to make sure you need them" is more clearly described by John. but let me briefly point it out again:
The request, as shown, is ostensibly correct and should perform as expected. What you are probably experiencing is a flaw in the logic of the surrounding code.
Chances are you are binding data in page_load without an IsPostback guard, thereby overwriting your input values with the original data.
You only need to load and bind the controls / page once on first load. After that, the state of the controls is stored in the viewstate, which is stored in a hidden field in html. If you just bind to the datasource on every page load, you will overwrite any input
So let's take a look at how it works.
Here is the correct logical flow
protected void Page_Load(object sender, EventArgs e)
{
System.Diagnostics.Trace.WriteLine("Page_Load");
if (!IsPostBack)
{
System.Diagnostics.Trace.WriteLine("\tBind TextBox1");
TextBox1.Text = "Initial Value";
}
System.Diagnostics.Trace.WriteLine("\tTextBox1.Text = " + TextBox1.Text);
}
protected void Button1_Click(object sender, EventArgs e)
{
System.Diagnostics.Trace.WriteLine("Button1_Click");
System.Diagnostics.Trace.WriteLine("\tTextBox1.Text = " + TextBox1.Text);
}
If you load this page, enter "New value" in the text box and click the "one" button, this shows the trace:
Page_Load
Bind TextBox1
TextBox1.Text = Initial Value
Page_Load
TextBox1.Text = New Value
Button1_Click
TextBox1.Text = New Value
But without protection:
protected void Page_Load(object sender, EventArgs e)
{
System.Diagnostics.Trace.WriteLine("Page_Load");
System.Diagnostics.Trace.WriteLine("\tBind TextBox1");
TextBox1.Text = "Initial Value";
System.Diagnostics.Trace.WriteLine("\tTextBox1.Text = " + TextBox1.Text);
}
protected void Button1_Click(object sender, EventArgs e)
{
System.Diagnostics.Trace.WriteLine("Button1_Click");
System.Diagnostics.Trace.WriteLine("\tTextBox1.Text = " + TextBox1.Text);
}
You are getting the results that you are probably experiencing ...
Page_Load
Bind TextBox1
TextBox1.Text = Initial Value
Page_Load
Bind TextBox1
TextBox1.Text = Initial Value
Button1_Click
TextBox1.Text = Initial Value
But then again, a practical debugging technique to help you is to break down the update method just before executing the query and check the values to make sure they are what you think they are, and then from there.
a source to share
If it still doesn't work, here are some debugging questions:
- Where is this code located and on what part of the page life cycle is it called?
- What's coming back
Lib.GetConnectionString(null)
? - Have you set any breakpoints before the update request to make sure you have the correct data?
My best guess is that since you are updating an existing record, it is very likely that your postback values will be overwritten on the Page_Load
existing data in the database, which means the query is actually being updated, but it is updating with the same exact data that already there.
What you want to do is check if(!IsPostBack)...
before filling in any of your text boxes on the page. Thus, if there is a postback, then the data in the text blocks will be populated with postback values and not with values from your database.
a source to share
Another thing you can try for quick troubleshooting is to use the SQL Server Profiler. It's easier to use than you might think. I promise!
- Run Sql Server Profiler (comes with Sql Server)
- Click File → New Trace
- Connect to your DB
- Accept the default tracing properties.
- Boom! This is a recording!
- Run the application. If you are already on the page refreshing it, refresh or click a button or something else that triggers the refresh.
- Examine the records that appear in the trace. It's all in real time!
- Optional: press the erase button and try again. You will be able to see the exact SQL that is being executed in the profiler.
- When you're done, hit the stop button.
a source to share
First, it is wildly susceptible to injection.
For more than a day, any input containing a single apostrophe will break the syntax. Does your data have apostrophe data?
EDIT - second idea
Be aware that you MUST call conn.Close();
to close the database connection as soon as you are done with it, otherwise the connection will remain open on the database server until garbage collection starts, t21> instance. Alternatively, see Construction using () {}
.
Slightly grabbing at straws here, but try an explicit transaction.
SqlTransaction trans;
conn.Open();
try
{
trans = conn.BeginTransaction();
int rows = cmd.ExecuteNonQuery();
trans.Commit();
}
catch
{
trans.Rollback();
}
conn.Close();
a source to share
Looking at the other discussion in this question, it appears that your query works, but something unrelated is wrong here. Some things to check that bite my ass sometimes:
-
Are you really sure you are fulfilling the request that you think you are? Go to the debugger before clicking
cmd.ExecuteNonQuery()
. Are the parameters what you think they are? Is the command text still what you think it should be? -
Are you updating the correct database? Break into the debugger and check your connection string (
cs
). Perhaps you are still connected to the production database if you want to develop one, or vice versa? -
What happens if you execute a query manually in SQL Management Studio? Has the line updated what you think it should?
a source to share
If contact_id is an integer, try not enclosing it in single quotes.
Edit:
"WHERE contact_id = '" + contact_id + "'";
to
"WHERE contact_id = " + contact_id;
Update: As John pointed out in a comment, there is no significant difference between the two articles. It is most likely faster to query without quotes because you are missing the cast / transform in this case.
a source to share