I'm working with two stored procedures in an ASP.NET button function. While I get an error message based on the results that the invoice number is already dispatched from the other stored procedure, it still moves to the other stored procedure and executes it.
If the user gets this error message:
This invoice num was already dispatched!
then it shouldn't move on to this aspect of the function
protected void Button2_Click(object sender, EventArgs e)
{
try
{
for (int i = GridView2.Rows.Count - 1; i >= 0; i--)
{
var row = GridView2.Rows[i];
CheckBox chk = row.FindControl("chkInvoice") as CheckBox;
//CheckBox chk = (CheckBox)GridView2.Rows[i].Cells[0].FindControl("CheckBox3");
if (chk != null && chk.Checked)
{
string strSQLconstring = System.Configuration.ConfigurationManager.ConnectionStrings["TWCL_OPERATIONSConnectionString"].ToString();
using (SqlConnection objConnection = new SqlConnection(strSQLconstring))
{
objConnection.Open();
using (SqlTransaction transaction = objConnection.BeginTransaction())
{
string SID = GridView2.Rows[i].Cells[3].Text.Trim();
SqlDataReader myReader = null;
using (SqlCommand command = new SqlCommand("PP_SelectStatus", objConnection, transaction))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#invoiceNum", SID);
command.Parameters.AddWithValue("#custPONum", GridView2.Rows[i].Cells[4].Text.Trim());
myReader = command.ExecuteReader();
if (myReader.Read())
{
string invoice1 = (myReader["status"].ToString());
if (invoice1 == "0")
{
ClientScript.RegisterClientScriptBlock(this.GetType(), "alert", "alert('This invoice num was already dispatched!')", true);
}
myReader.Close();
}
}
else if (invoice1=="1")
{
using (SqlCommand cmd = new SqlCommand("PP_RemoveInvoice", objConnection, transaction))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#loadSheetNum", txtDispatchNum.Text);
cmd.Parameters.AddWithValue("#invoiceNum", SID);
cmd.Parameters.AddWithValue("#removeUser", lblUsername.Text.Replace("Welcome", ""));
**int a = cmd.ExecuteNonQuery();**
cmd.Dispose();
if (a > 0)
{
dt.Rows.RemoveAt(i);
////Read invoice qty from grid view 2
string invoice = GridView2.Rows[i].Cells[5].Text.ToString();
decimal invoiceTotal = Convert.ToDecimal(txtInvoiceTotal.Text) - Convert.ToDecimal(invoice);
txtInvoiceTotal.Text = invoiceTotal.ToString();
////Read invoice weight from grid view 2
string weight = GridView2.Rows[i].Cells[6].Text.ToString();
decimal invoiceWeight = Convert.ToDecimal(txtQtyWeight.Text) - Convert.ToDecimal(weight);
txtQtyWeight.Text = invoiceWeight.ToString();
lblError.ForeColor = Color.Green;
lblError.Text = "Selected record(s) successfully updated";
}
else
{
lblError.ForeColor = Color.Red;
lblError.Text = " Record has not yet been recorded";
}
}
//objConnection.Close();
transaction.Commit();
}
}
}
//Button2.Visible = false;
//showData();
GridView2.DataSource = dt;
GridView2.DataBind();
txtInvoiceCount.Text = dt.Rows.Count.ToString();
}
}
}
catch (Exception ex)
{
if (ex.Message.StartsWith("Violation of PRIMARY KEY constraint"))
{
lblError.ForeColor = Color.Red;
lblError.Text = " This invoice number was remove from dispatch sheet before!!";
}
else
{
// re-throw the error if you haven't handled it
lblError.Text = ex.Message;
throw;
}
}
}
You have a very, very simple logic error, but it is incredibly hard to see because your code is such a mess. Therefore, my answer is:
REFACTOR REFACTOR REFACTOR
It is important to get into the habit of writing short functions and controlling their inputs and outputs. If you don't do this, even a fairly trivial operation like this one gets very confusing and error-prone.
Here is an example of how to organize things. We remove most of the code from the click handler:
protected void DeleteButton_Click(object sender, EventArgs e)
{
for (int i = GridView2.Rows.Count - 1; i >= 0; i--)
{
var row = GridView2.Rows[i];
if (IsChecked(row))
{
var result = ProcessRow(row, i);
DisplayResult(i, result);
}
}
}
Firstly, notice it has a meaningful name. These become very important as your application grows. Also, look how short it is! Where did all the code go? Well, it went into two separate methods, which are now short enough for us to view on one page-- a common requirement that IT organizations impose on their programmers, to avoid spaghetti code.
protected TransactionResult ProcessRow(GridViewRow row, int index)
{
var SID = GridView2.Rows[index].Cells[3].Text.Trim();
var custPONum = GridView2.Rows[index].Cells[4].Text.Trim();
var loadSheetNum = txtDispatchNum.Text;
var removeUser = lblUsername.Text.Replace("Welcome", "");
return ExecuteInvoiceTransaction(SID, custPONum, loadSheetNum, removeUser);
}
And
public void DisplayResult(int rowIndex, TransactionResult result)
{
switch result
{
case TransactionResult.Success:
dt.Rows.RemoveAt(rowIndex);
DisplayTotals(rowIndex);
DisplaySuccess("Selected record(s) successfully updated");
break;
case TransactionResult.AlreadyDispatched;
ClientScript.RegisterClientScriptBlock(this.GetType(), "alert", "alert('This invoice num was already dispatched!')", true);
break;
case TransactionResult.RecordNotRecorded;
DisplayError("Record has not yet been recorded");
break;
case TransactionResult.AlreadyRemoved:
DisplayError("This invoice number was remove from dispatch sheet before!!");
break;
}
}
These methods in turn call a variety of helper methods, each of which does one thing and one thing only. This could be referred to as separation of concerns, which is really important for structured code.
Here's the rest of the methods:
enum TransactionResult
{
Success,
AlreadyDispatched,
RecordNotRecorded,
AlreadyRemoved
}
private bool ExecuteSelectStatus(SqlConnection connection, SqlTransaction transaction, string invoiceNum, string custPONum)
{
using (SqlCommand command = new SqlCommand("PP_SelectStatus", objConnection, transaction))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#invoiceNum", invoiceNum);
command.Parameters.AddWithValue("#custPONum", custPONum);
using (var myReader = command.ExecuteReader())
{
if (myReader.Read())
{
string invoice1 = (myReader["status"].ToString());
if (invoice1 == "0")
{
return false;
}
}
}
return true;
}
}
private int ExecuteRemoveInvoice(SqlConnection objConnection, SqlTransaction transaction, string loadSheetNum, string invoiceNum, string removeUser)
{
try
{
using (SqlCommand cmd = new SqlCommand("PP_RemoveInvoice", objConnection, transaction))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#loadSheetNum", loadSheetNum);
cmd.Parameters.AddWithValue("#invoiceNum", invoiceNum);
cmd.Parameters.AddWithValue("#removeUser", removeUser);
return cmd.ExecuteNonQuery();
}
}
catch (SqlException ex)
{
if (ex.Number == 2627) //Primary key violation
{
return -1;
}
}
}
protected TransactionResult ExecuteInvoiceTransaction(string invoiceNum, string custPONum, string loadSheetNum, string removeUser)
{
var strSQLconstring = System.Configuration.ConfigurationManager.ConnectionStrings["TWCL_OPERATIONSConnectionString"].ToString();
using (SqlConnection objConnection = new SqlConnection(strSQLconstring))
{
objConnection.Open();
using (SqlTransaction transaction = objConnection.BeginTransaction())
{
var ok = ExecuteSelectStatus(objConnection, transaction, invoiceNum, custPONum);
if (!ok) return TransactionResult.AlreadyDispatched;
var a = ExecuteRemoveInvoice(objConnection, transaction, loadSheetNum, invoiceNum, removeUser);
switch a
{
case -1:
return TransactionResult.AlreadyRemoved;
case 0:
return TransactionResult.RecordNotRecorded;
default:
transaction.Commit();
return TransactionResult.Success;
}
}
}
}
public void DisplayTotals(int i)
{
////Read invoice qty from grid view 2
string invoice = GridView2.Rows[i].Cells[5].Text;
decimal invoiceTotal = Convert.ToDecimal(txtInvoiceTotal.Text) - Convert.ToDecimal(invoice);
txtInvoiceTotal.Text = invoiceTotal.ToString();
////Read invoice weight from grid view 2
string weight = GridView2.Rows[i].Cells[6].Text();
decimal invoiceWeight = Convert.ToDecimal(txtQtyWeight.Text) - Convert.ToDecimal(weight);
txtQtyWeight.Text = invoiceWeight.ToString();
}
public void DisplaySuccess(string message)
{
lblError.ForeColor = Color.Green;
lblError.Text = message;
}
public void DisplayError(string message)
{
lblError.ForeColor = Color.Red;
lblError.Text = message;
}
A few things to note:
You don't need to call Dispose() if you are using using.
You should always catch the most specific exception possible, per Microsoft's guidance. My example does this.
The exception handling for the primary key error is isolated into the method that calls the stored procedure. The overall business logic shouldn't have to know details about the SQL implementation. I've shown how you can identify the specific error based on this post.
Because there are four possible outcomes, I added an enumeration called TransactionResult so we could return the status to the caller easily.
Some of these methods are short-- just two lines-- and that is OK. The main reason to separate them out is to give them a meaningful name and make the code shorter and easier to read.
This code is much more structured but it could still be improved! In many implementations, the code that accesses the database is actually moved to a completely different layer or project.
See if this works. Moved your if/else together:
protected void Button2_Click(object sender, EventArgs e)
{
try
{
for (int i = GridView2.Rows.Count - 1; i >= 0; i--)
{
var row = GridView2.Rows[i];
CheckBox chk = row.FindControl("chkInvoice") as CheckBox;
if (chk != null && chk.Checked)
{
string strSQLconstring = System.Configuration.ConfigurationManager.ConnectionStrings["TWCL_OPERATIONSConnectionString"].ToString();
using (SqlConnection objConnection = new SqlConnection(strSQLconstring))
{
objConnection.Open();
using (SqlTransaction transaction = objConnection.BeginTransaction())
{
string SID = GridView2.Rows[i].Cells[3].Text.Trim();
SqlDataReader myReader = null;
using (SqlCommand command = new SqlCommand("PP_SelectStatus", objConnection, transaction))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("#invoiceNum", SID);
command.Parameters.AddWithValue("#custPONum", GridView2.Rows[i].Cells[4].Text.Trim());
myReader = command.ExecuteReader();
if (myReader.Read())
{
string invoice1 = (myReader["status"].ToString());
if (invoice1 == "0")
{
ClientScript.RegisterClientScriptBlock(this.GetType(), "alert", "alert('This invoice num was already dispatched!')", true);
}
else if (invoice1 == "1")
{
using (SqlCommand cmd = new SqlCommand("PP_RemoveInvoice", objConnection, transaction))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#loadSheetNum", txtDispatchNum.Text);
cmd.Parameters.AddWithValue("#invoiceNum", SID);
cmd.Parameters.AddWithValue("#removeUser", lblUsername.Text.Replace("Welcome", ""));
int a = cmd.ExecuteNonQuery();
cmd.Dispose();
if (a > 0)
{
dt.Rows.RemoveAt(i);
////Read invoice qty from grid view 2
string invoice = GridView2.Rows[i].Cells[5].Text.ToString();
decimal invoiceTotal = Convert.ToDecimal(txtInvoiceTotal.Text) - Convert.ToDecimal(invoice);
txtInvoiceTotal.Text = invoiceTotal.ToString();
////Read invoice weight from grid view 2
string weight = GridView2.Rows[i].Cells[6].Text.ToString();
decimal invoiceWeight = Convert.ToDecimal(txtQtyWeight.Text) - Convert.ToDecimal(weight);
txtQtyWeight.Text = invoiceWeight.ToString();
lblError.ForeColor = Color.Green;
lblError.Text = "Selected record(s) successfully updated";
}
else
{
lblError.ForeColor = Color.Red;
lblError.Text = " Record has not yet been recorded";
}
}
//objConnection.Close();
transaction.Commit();
}
}
}
GridView2.DataSource = dt;
GridView2.DataBind();
txtInvoiceCount.Text = dt.Rows.Count.ToString();
}
}
}
}
}
catch (Exception ex)
{
if (ex.Message.StartsWith("Violation of PRIMARY KEY constraint"))
{
lblError.ForeColor = Color.Red;
lblError.Text = " This invoice number was remove from dispatch sheet before!!";
}
else
{
// re-throw the error if you haven't handled it
lblError.Text = ex.Message;
throw;
}
}
}
}
I am trying to filter the gridview with the help of a few checkboxlists and it works absolutely fine.It is all real time since i am using a update panel.Now when i try to add one more filer i.e couple of datepickers to filter the gridview depending on the two dates,it gives me the error message " Incorrect syntax near the keyword 'and'.". The entire code is given below :
private void BindGrid()
{
string CS = ConfigurationManager.ConnectionStrings["SportsActiveConnectionString"].ConnectionString;
string query = "Select * from tblAllEvents";
string condition = string.Empty;
string conditionDisability = string.Empty;
string conditionDates = string.Empty;
foreach (ListItem item in cblGender.Items)
{
condition += item.Selected ? string.Format("'{0}',", item.Value) : string.Empty;
}
if (!string.IsNullOrEmpty(condition))
{
condition = string.Format(" Where Gender IN ({0})", condition.Substring(0, condition.Length - 1));
}
else
{
condition = string.Format(" Where Gender IN ('Male','Female','Mixed')", condition.Substring(0,Math.Max(0,condition.Length - 1)));
}
foreach (ListItem item in cblDisability.Items)
{
conditionDisability += item.Selected ? string.Format("'{0}',", item.Value) : string.Empty;
}
if (!string.IsNullOrEmpty(conditionDisability))
{
conditionDisability = string.Format(" and Disabled IN ({0})", conditionDisability.Substring(0, conditionDisability.Length - 1));
}
if(txtEventStart.Text == null)
{
txtEventStart.Text = "01/01/1900";
}
if(txtEventEnd.Text == null)
{
txtEventEnd.Text = "01/01/2050";
}
conditionDates = string.Format(" and EventStart between {0} and {1}",txtEventStart.Text,txtEventEnd.Text);
using (SqlConnection con = new SqlConnection(CS))
{
using (SqlCommand cmd = new SqlCommand(query + condition + conditionDisability + conditionDates))
{
using (SqlDataAdapter sda = new SqlDataAdapter(cmd))
{
cmd.Connection = con;
using (DataTable dt = new DataTable())
{
sda.Fill(dt);
GridView1.DataSource = dt;
GridView1.DataBind();
}
}
}
}
}
Please note the problem arises on when i include 'conditionDates' in the query. What can be the other ways to make the query work.
Edit : As i said earlier, the problem lies in the below code
if(txtEventStart.Text == null)
{
txtEventStart.Text = "01/01/1900";
}
if(txtEventEnd.Text == null)
{
txtEventEnd.Text = "01/01/2050";
}
conditionDates = string.Format(" and EventStart between {0} and {1}",txtEventStart.Text,txtEventEnd.Text);
You are missing apostrophes around the values:
conditionDates = string.Format(" and EventStart between '{0}' and '{1}'", txtEventStart.Text, txtEventEnd.Text);
Note however that code like this is wide open for SQL injection attacks. You should use parameters in the query instead:
conditionDates = " and EventStart between #EventStart and #EventEnd";
Then you add parameters to the command object parameter collection to supply the values to the query:
cmd.Parameters.Add("#EventStart", SqlDbType.DateTime).Value = txtEventStart.Text;
cmd.Parameters.Add("#EventEnd", SqlDbType.DateTime).Value = txtEventEnd.Text;
You clearly have a SQL syntax error. First debug your code and get the resulting query and run it separately in SQL Server. You will inspect it better in that way.
It's about how you are concatenating the SQL query when you add that part.
I have DropdownList which I populate at the time of Page_Load
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
DataTable table = new DataTable();
string connectionString = GetConnectionString();
string sqlQuery = "select distinct sname from contacts where sname is not null";
using (OracleConnection conn = new OracleConnection(connectionString))
{
try
{
conn.Open();
using (OracleCommand cmd = new OracleCommand(sqlQuery, conn))
{
using (OracleDataAdapter ODA = new OracleDataAdapter(cmd))
{
ODA.Fill(table);
}
}
}
catch (Exception ex)
{
Response.Write("Not Connected" + ex.ToString());
}
}
//DropDownList1.DataSource = table;
//DropDownList1.DataValueField = "";
DropDownList2.DataSource = table;
DropDownList2.DataValueField = "sname";
DropDownList2.DataTextField = "sname";
DropDownList2.DataBind();
}
}
Now I am trying to populate a GridView when the DropDownList's Item changes
protected void DropDownList2_SelectedIndexChanged(object sender, EventArgs e)
{
DataTable table = new DataTable();
string connectionString = GetConnectionString();
string val = DropDownList2.SelectedValue;
string sqlQuery = "SELECT distinct DUTY_DATE FROM DUTY_ROTA,DUTY_TYPES,CONTACTS WHERE DUTY_DATE between SYSDATE and SYSDATE+30 AND DUTY_ROTA.DUTY_TYPE = DUTY_TYPES.DUTY_TYPE AND SNAME IS NOT NULL and contacts.sname = '" + val + "' ORDER BY DUTY_DATE";
using (OracleConnection conn = new OracleConnection(connectionString))
{
try
{
conn.Open();
using (OracleCommand cmd = new OracleCommand(sqlQuery, conn))
{
using (OracleDataAdapter ODA = new OracleDataAdapter(cmd))
{
ODA.Fill(table);
}
}
}
catch (Exception ex)
{
Response.Write("Not Connected" + ex.ToString());
}
}
GridView1.DataSource = table;
GridView1.DataBind();
}
I have enabled the AutoPostBack. Now when I am changing a DropDownList item to a different one the Page is loading but always retaining the first value. I tried to debug , I found that
string val = DropDownList2.SelectedValue;
the val variable is always the first value that is returned by the Query. Can anybody please tell me how could I get rid of this. I want to populate the GridView whenever I am selecting any item in the dropdown.
Hi i think that dropdownlist charge again when you select other item. Put a Break Point in Page Load and look if your dropdownlist charge again i don't see other reason. Good Luck
Your Drop downlist should look like as following :
<asp:DropDownList ID="DropDownList2" runat="server" AutoPostBack="True"
OnSelectedIndexChanged="DropDownList2_SelectedIndexChanged">
</asp:DropDownList>
Make sure AutoPostBack is Set to TRUE.
One more thing you can try is to select the item when the index is greater than -1.
if(DropDownList2.SelectedIndex != -1)
{
string val = DropDownList2.SelectedItem.Value;
// enter code here
}
I want to update multi checkboxlist value to the the database. I already databound my checkboxlist from other table which is the medicine table. Now i want to update my value to consultation table, but i can not
`
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
try
{
for (int i = 0; i < txtcheckbox.Items.Count - 1; i++)
{
if (txtcheckbox.Items[i].Selected == true)
{
str = str + txtcheckbox.Items[i].Text + ",";
}
}
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
String sql = "UPDATE [consultation] set mname3 = " + str + " WHERE [conid] = #conid";
con.Open();
SqlCommand cmd = new SqlCommand(sql, con);
cmd.Parameters.AddWithValue("#conid", txtconid);
cmd.Parameters.AddWithValue("#mname3", str);
int j = cmd.ExecuteNonQuery();
if (j > 0)
{
Label2.Visible = true;
Label2.Text = "Successfully Complete Dispensary";
txtconid.Text = "";
}
else
{
Label2.Visible = true;
Label2.Text = "Not Successfully Complete Dispensary";
txtconid.Text = "";
}
con.Close();
}
catch
{
Label2.Visible = true;
Label2.Text = "Error";
txtconid.Text = "";
}
}
`
I guess you have exception here. Because:
String sql = "UPDATE [consultation] set mname3 = " + str + " WHERE [conid] = #conid";
here you use concatenation of strings and your sql query will look like:
UPDATE [consultation] set mname3 = sometextvale WHERE [conid] = #conid
mname3 have nvarchar sql type I guess, so you need to put string value in qoutes:
String sql = "UPDATE [consultation] set mname3 = ' " + str + " ' WHERE [conid] = #conid";
Or you can use paramaeter for sql query, like you already did for #conid:
String sql = "UPDATE [consultation] set mname3 = #mname3 WHERE [conid] = #conid";
It's better solution in security way.
Some additional comments:
for (int i = 0; i < txtcheckbox.Items.Count - 1; i++)
Are you sure here should be txtcheckbox.Items.Count - 1? You will lost the last one.
And the 2nd one: Mix code for construction and execution query (DAL) in code behind of page with some kind of business logic not a good practice =)
Hello in my programme I need to create dynamically checkboxlist with items - got from teh database.
The problem is when Clicking a button i should get the text from cn only checked checkboxes and I should redirect the user to another page
And I have difficulty with determining width of the controls are checkedore
if I checked immediately after they are added
So if I write
if (mycheckbox.Items[s].Selected==true)
after this line
Page.FindControl("form1").Controls.Add(mycheckbox);
they are not checked still so this will be always false)
On postback event (clicking the button ) - we know on postback event dynamic controls no longer exist)
here is my code
protected void ddlNumberTourists_SelectedIndexChanged(object sender, EventArgs e)
{
int numTourists = Convert.ToInt32(ddlNumberTourists.SelectedItem.Text);
for (int i = 0; i < numTourists; i++)
{
string connectionString = "Server=localhost\\SQLEXPRESS;Database=excursion;Trusted_Connection=true";
string query =
"SELECT Extra_Charge_ID, Excursion_ID, Amout, Extra_Charge_Description FROM EXTRA_CHARGES WHERE Excursion_ID=" + mynewstring;
SqlConnection conn = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand(query, conn);
try
{
conn.Open();
SqlDataReader rd = cmd.ExecuteReader();
int s = 0;
while (rd.Read())
{
mycheckbox.ID = "chkblextracharge" + i.ToString() + s.ToString();
mycheckbox.Items.Add(rd["Extra_Charge_Description"].ToString());
Page.FindControl("form1").Controls.Add(mycheckbox);
s++;
}
}//End of try
catch (Exception ex)
{ }
}//end of for
I've implemented a client-side check using jQuery in my online Quiz engine (demo: http://webinfocentral.com): the extract from that code snippet follows:
var _rows = $(this).find('tr');
for (i = 0; i < _rows.length; i++) {
// find out if checkbox is checked
_checked = $(_rows[i]).find('input:checkbox').is(':checked');
}
conn.Open();
SqlDataReader rd = cmd.ExecuteReader();
int s = 0;
mycheckboxList = new CheckBoxList();
mycheckboxList.ID = "chkblextracharge" + i.ToString();
while (rd.Read())
{
ListItem LI = new ListItem(rd["Extra_Charge_Description"].ToString(), s.ToString());
LI.Selected = rd["Selected_Criteria"] == "TRUE";
mycheckboxList.Items.Add(LI);
s++;
}
Page.FindControl("form1").Controls.Add(mycheckboxList);