One time record insertion then update many times - c#

I have a form where a user can insert, view and update data. Data insertion is done only once, then updates can be done many times. By default, the user will be able to view the data if it exists in the database.
I tried this but it doesn't insert into database. Then suppose a data exists in database and when the user wants to update the record, it throws an error - DataReader is open.
private void display_Emp()
{
try
{
using (sqlCon = new SqlConnection(ConfigurationManager.ConnectionStrings["Connection"].ConnectionString))
{
sqlCon.Open();
SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Employee", sqlCon);
DataSet ds = new DataSet("Employee");
da.Fill(ds, "Employee");
int x = 0;
for (x = 0; x < ds.Tables[0].Rows.Count; x++)
{
txtID.Text = ds.Tables[0].Rows[x][1].ToString();
txtEmpName.Text = ds.Tables[0].Rows[x][2].ToString();
}
}
}
catch(Exception exx) {
MessageBox.Show(exx.Message);
}
finally {
sqlCon.Close();
}
}
private void btnSave_Click(object sender, EventArgs e)
{
try
{
using (sqlCon = new SqlConnection(ConfigurationManager.ConnectionStrings["Connection"].ConnectionString))
{
sqlCon.Open();
SqlCommand com = new SqlCommand("SELECT * FROM Employee", sqlCon);
read = com.ExecuteReader();
while (read.Read())
{
if (read.HasRows)
{
SqlCommand update = new SqlCommand("UPDATE Employee SET EmpID = '" + txtID.Text + "' , EmpName = '" + txtEmpName.Text + "', sqlCon);
update.ExecuteNonQuery();
MessageBox.Show("Employee details updated!", "Employee", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
SqlCommand comm = new SqlCommand("INSERT INTO Employee(EmpID, EmpName) VALUES ('" + txtID.Text + "','" + txtEmpName.Text + "')", sqlCon);
comm.ExecuteNonQuery();
MessageBox.Show("Employee details saved!", "Employee", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
read.Close();
sqlCon.Close();
}
}
EDIT:
Table:- Deepz (ID int PK, Goodname varchar(50) )
DECLARE #ID int
DECLARE #Goodname varchar(50)
MERGE Deepz t
USING (SELECT #ID[ID], #Goodname[Goodname]) s
ON (t.ID = s.ID)
WHEN MATCHED THEN
UPDATE
SET t.Goodname = #Goodname
WHEN NOT MATCHED THEN
INSERT (ID, Goodname)
VALUES (#ID, #Goodname);
Errors:
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near 't'.
Msg 137, Level 15, State 2, Line 2
Must declare the scalar variable "#ID".

You should change your save functionality to:
If you're on SQL Server 2008 or later, use SQL Merge statement to insert or update depending on whether record exists or not
DECLARE #nameField VarChar(50) = 'some data'
MERGE dbo.MyTable t
USING (SELECT #nameField [field]) s
ON t.myData = s.field
WHEN MATCHED THEN
UPDATE
SET t.myData = #nameField
WHEN NOT MATCHED THEN
INSERT (myData)
VALUES (#nameField);
If you are on SQL Server 2005 or earlier, you will need to use something like below, but you may have a race condition (but imho will still be better than your original design, which has the potential for a race condition as well) so depending on your environment you may need to play around with locks, etc
IF EXISTS (SELECT * FROM Deepz WHERE [ID] = #ID)
BEGIN
UPDATE Deepz
SET Goodname = #Goodname
WHERE [ID] = #ID
END
ELSE
BEGIN
INSERT Deepz (ID, Goodname)
VALUES (#ID, #Goodname);
END
Use sql params instead of building the statement by concatenation, will save you from SQL injection attacks
UPDATE Employee SET EmpID = #id, EmpName = #name
then
SqlCommand comm = new SqlCommand(...);
// note below is a bit simplified, in reality you should do int.TryParse
comm.Parameters.Add(#id, SqlDbType.Int).Value = int.Parse(txtID.Text);

This is a bit of a shot in the dark but, try this:
private void btnSave_Click(object sender, EventArgs e)
{
try
{
using (sqlCon = new SqlConnection(ConfigurationManager.ConnectionStrings["Connection"].ConnectionString))
{
sqlCon.Open();
SqlCommand com = new SqlCommand("SELECT * FROM Employee", sqlCon);
com.Parameters.AddWithValue(#empID, SqlDbType.Int).Value = int.Parse(txtID.Text); // Add this line
com.Parameters.AddWithValue(#empName, SqlDbType.NVarChar).Value = txtEmpName.Text; // Add this line too
SqlDataReader read = new SqlDataReader(); // You also need to 'new' up your SqlDataReader.
read = com.ExecuteReader();
while (read.Read())
{
if (read.HasRows)
{
SqlCommand update = new SqlCommand("UPDATE Employee SET EmpID = #empID, EmpName = #empName", sqlCon);
update.ExecuteNonQuery();
MessageBox.Show("Employee details updated!", "Employee", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
SqlCommand comm = new SqlCommand("INSERT INTO Employee(EmpID, EmpName) VALUES (#empID, #empName)", sqlCon);
comm.ExecuteNonQuery();
MessageBox.Show("Employee details saved!", "Employee", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
read.Close();
sqlCon.Close();
}
}

From the examples i'm looking at the "If" condition and "While" condition look like they are inverted.
http://msdn.microsoft.com/en-us/library/haa3afyz%28v=vs.80%29.aspx
You check to see if there are rows first and then iterate over them

Related

Delete Command C# + SQL Server

I'm performing a command to erase data from a DataGridView
But I can not make it work, I just want to select a line and erase it
In addition to programming a button that says "Delete" so that when you click on it, the selected data in the DataGridView will be deleted
I need really help
I am lost
My Table is "Person"
My Column is "ID"
Instances
{SqlConnection cn;
SqlCommand cmd;
SqlDataReader dr;
SqlDataAdapter da;
DataTable dt;}
public string Del(int ID)
{
string ouk = "Delete Work";
try
{
cmd = new SqlCommand("Delete From Person Where = ID )", cn);
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
ouk = "Bad character:" + ex.ToString();
}
return ouk;
}
For Button Erase at DataGridView
private void buttondel_Click(object sender, EventArgs e)
{
MessageBox.Show(c.Del(TBID));
}
The issue is that your SQL query is malformed and that you're not passing the ID to the query:
"Delete From Person Where = ID )"
One side of the equality check is missing, and you have an unexpected closing bracket.
You should change your query to accept a parameter:
"Delete From Person Where ID = #id"
and then pass the parameter to your command:
cmd.Parameters.Add("#id", SqlDbType.Int).Value = ID;
So it becomes:
try
{
using (cmd = new SqlCommand("Delete From Person Where ID = #id", cn))
{
cmd.Parameters.Add("#id", SqlDbType.Int).Value = ID;
cmd.ExecuteNonQuery();
}
}
catch (Exception ex)
{
ouk = "Bad character:" + ex.ToString();
}
I've taken the liberty of wrapping SqlCommand in a using statement so that it's disposed once we're done with it.

Updating records in SQL Server database using ASP.NET

I am new to ASP.NET, I am facing some difficulty in updating records inside database in ASP.NET. My code is showing no errors, but still the records are not being updated. I am using SQL Server 2012.
Code behind is as follows:
protected void Page_Load(object sender, EventArgs e)
{
if (Session["user"] != null)
{
con.Open();
string query = "Select * from Customers where UserName ='" + Session["user"] + "'";
SqlCommand cmd = new SqlCommand(query, con);
SqlDataReader reader = cmd.ExecuteReader();
if (reader.Read())
{
txt_name.Text = reader["CustName"].ToString();
txt_phonenumber.Text = reader["Contact"].ToString();
txt_address.Text = reader["CustAddress"].ToString();
txt_cardnum.Text = reader["CustAccountNo"].ToString();
txt_city.Text = reader["CustCity"].ToString();
txt_emailaddress.Text = reader["Email"].ToString();
txt_postalcode.Text = reader["CustPOBox"].ToString();
Cnic.Text = reader["CustCNIC"].ToString();
}
con.Close();
}
else
{
Response.Redirect("Login.aspx");
}
}
protected void BtnSubmit_Click(object sender, EventArgs e)
{
con.Open();
SqlCommand cmd2 = con.CreateCommand();
SqlCommand cmd1 = con.CreateCommand();
cmd1.CommandType = CommandType.Text;
cmd1.CommandText = "Select CustID from Customers where UserName = '" + Session["user"] + "'";
int id = Convert.ToInt32(cmd1.ExecuteScalar());
cmd2.CommandType = CommandType.Text;
cmd2.CommandText = "update Customers set CustName='" + txt_name.Text + "',CustCNIC='" + Cnic.Text + "',Email='" + txt_emailaddress.Text + "',CustAccountNo='" + txt_cardnum.Text + "',CustAddress='" + txt_address.Text + "',CustPOBox='" + txt_postalcode.Text + "' where CustID='" + id + "'";
cmd2.ExecuteNonQuery();
con.Close();
}
Help will be much appreciated. THANKS!
After debugging the result i am getting is this
cmd2.CommandText "update Customers set CustName='Umer Farooq',CustCNIC='42101555555555',Email='adada#gmail.com',CustAccountNo='0',CustAddress='',CustPOBox='0' where CustID='6'" string
Here Account Number And POBOX is 0 and address is going as empty string. But i have filled the text fields
First thing to do to fix this is to use good ADO techniques, using SqlParameters for the passed in values; and not the risky SQL Injection method of concatenating strings together.
This first portion does just that. I have added in the int sqlRA variable to read the results of the non-query, which will return Rows Affected by the query. This is wrapped in a simple try...catch routine to set the value to negative 1 on any error. Other error handling is up to you. That makes your code look something like this:
cmd1.Parameters.AddWithValue("#SessionUser", Session["User"]);
int id = Convert.ToInt32(cmd1.ExecuteScalar());
cmd2.CommandType = CommandType.Text;
cmd2.CommandText = "UPDATE Customers SET CustName = #CustName, CustCNIC = #CustCNIC, Email = #Email, CustAccountNo = #CustAccountNo, CustAddress = #CustAddress, CustPOBox = #CustPOBox WHERE (CustID = #CustID)";
cmd2.Parameters.AddWithValue("#CustName", txt_name.Text);
cmd2.Parameters.AddWithValue("#CustCNIC", Cnic.Text);
cmd2.Parameters.AddWithValue("#Email", txt_emailaddress.Text);
cmd2.Parameters.AddWithValue("#CustAccountNo", txt_cardnum.Text);
cmd2.Parameters.AddWithValue("#CustAddress", txt_address.Text);
cmd2.Parameters.AddWithValue("#CustPOBox", txt_postalcode.Text);
cmd2.Parameters.AddWithValue("#CustID", id);
int sqlRA
try { sqlRA = cmd2.ExecuteNonQuery(); }
catch (Exception ex) {
sqlRA = -1;
// your error handling
}
/* sqlRA values explained
-1 : Error occurred
0 : Record not found
1 : 1 Record updated
>1 :Multiple records updated
*/
Now reading through your code, all we are doing with the first query is mapping the Session["User"] to id, and then using that id in the second query to do the update, and that Username is not updated in the second. Waste of a query most likely, as we could use the Session["User"] to do the update. That will bring you down to this query, and still bring back that Rows Affected value back:
cmd0.CommandType = CommandType.Text;
cmd0.CommandText = "UPDATE Customers SET CustName = #CustName, CustCNIC = #CustCNIC, Email = #Email, CustAccountNo = #CustAccountNo, CustAddress = #CustAddress, CustPOBox = #CustPOBox WHERE (UserName = #SessionUser)";
cmd0.Parameters.AddWithValue("#CustName", txt_name.Text);
cmd0.Parameters.AddWithValue("#CustCNIC", Cnic.Text);
cmd0.Parameters.AddWithValue("#Email", txt_emailaddress.Text);
cmd0.Parameters.AddWithValue("#CustAccountNo", txt_cardnum.Text);
cmd0.Parameters.AddWithValue("#CustAddress", txt_address.Text);
cmd0.Parameters.AddWithValue("#CustPOBox", txt_postalcode.Text);
cmd0.Parameters.AddWithValue("#SessionUser", Session["User"]);
int sqlRA
try { sqlRA = cmd0.ExecuteNonQuery(); }
catch (Exception ex) {
sqlRA = -1;
// your error handling
}
/* sqlRA values explained
-1 : Error occurred
0 : Record not found
1 : 1 Record updated
>1 :Multiple records updated
*/
When BtnSubmit fires the event, the code in the Page_Load runs before the codes in BtnSubmit, replacing the values placed in the TextBox with the values from the Database before the Update takes place.

Check for duplicate entries before insertion (C#.net)

I have a textbox form that students fill out about their general information such as first and last name, city, state, etc. Sometimes a student can't remember if they filled out the form before and it will lead to duplicate entries in the ms-access database. Ideally I would like the code to first search the ms-access database for a matching first name AND last name on the same record before insertion. If there's a record that matches on both the entered first and last name fields then a script would run and say something like, "A matching record already exists, would you like to continue?" Clicking "Yes" would enter the record into a new row, clicking "Cancel" would not enter it into the database at all.
I started this code but I'm not sure if it's the right direction, any guidance would be appreciated, thanks.
using (OleDbConnection con = new OleDbConnection(constr))
using (OleDbCommand com = new OleDbCommand("SELECT COUNT(*) FROM StudentList WHERE [FName] = #FName AND [LName] = #LName", con))
{
con.Open();
using (OleDbDataReader myReader = com.ExecuteReader())
{
(This is where I am stuck)
}
}
Below is the current code for the submit button.
protected void btnSubmit_Click(object sender, EventArgs e)
{
{
//Preforms insert statement on click to allow additions to the database
DateTime CurrentDate;
CurrentDate = DateTime.Now;
string constr = #"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=D:\sites\schoolinfo\students_dev\App_Data\Studentdb.mdb";
string cmdstr = "INSERT into StudentList(FName, LName, BDay, Gender, School, Grade, Address, APT, City, State, Zip, Email, Phone, CellPhone, ParentFName, ParentLName, ParentEmail) values(#FName, #LName, #BDay, #Gender, #School, #Grade, #Address, #APT, #City, #State, #Zip, #Email, #Phone, #CellPhone, #ParentFName, #ParentLName, #ParentEmail)";
OleDbConnection con = new OleDbConnection(constr);
OleDbCommand com = new OleDbCommand(cmdstr, con);
{
con.Open();
}
//The following fields are added from the student information to the corresponding database fields
com.Parameters.AddWithValue("#FName", txtFirstName.Text);
com.Parameters.AddWithValue("#LName", txtLastName.Text);
com.Parameters.AddWithValue("#BDay", txtBirthDate.Text);
com.Parameters.AddWithValue("#Gender", ddlGender.Text);
com.Parameters.AddWithValue("#School", txtSchool.Text);
com.Parameters.AddWithValue("#Grade", txtGrade.Text);
//The following fields are added from the contact information to the corresponding database fields
com.Parameters.AddWithValue("#Address", txtAddress.Text);
com.Parameters.AddWithValue("#APT", txtApt.Text);
com.Parameters.AddWithValue("#City", txtCity.Text);
com.Parameters.AddWithValue("#State", ddlState.Text);
com.Parameters.AddWithValue("#Zip", txtZip.Text);
com.Parameters.AddWithValue("#Email", txtEmail.Text);
com.Parameters.AddWithValue("#Phone", txtPhone.Text);
com.Parameters.AddWithValue("#CellPhone", txtCellPhone.Text);
com.Parameters.AddWithValue("#ParentFName", txtParentFName.Text);
com.Parameters.AddWithValue("#ParentLName", txtParentLName.Text);
com.Parameters.AddWithValue("#ParentEmail", txtParentEmail.Text);
com.ExecuteNonQuery();
con.Close();
//End database connection
ScriptManager.RegisterClientScriptBlock(this, this.GetType(), "alertMessage", "alert('Student has been successfully added!')", true);
}
}
using (OleDbConnection con = new OleDbConnection(constr))
using (OleDbCommand com = new OleDbCommand("SELECT COUNT(*) FROM StudentList WHERE [FName] = #FName AND [LName] = #LName", con))
{
// Add your #Fname and #LName parameters here
com.Parameters.AddWithValue("#FName", firstName);
com.Parameters.AddWithValue("#LName", lastName);
con.Open();
using (OleDbDataReader myReader = com.ExecuteReader())
{
myReader.Read();
int count = myReader.GetInt32(0);
// return count > 0 or whatever to indicate that it exists
}
}
couple of things:
you can set in your table the first name and last name as 1 primary key (yes it possible in ms-access). this way you will NEVER get any duplicate records
count(*) is not the best practice with databases.. but since you are dealing with ms-access
using (OleDbDataReader myReader = com.ExecuteReader())
{
// reads the first and only column count(*) and convert it to a number
if (Convert.ToInt16(myReader[0]) > 0)
{
// an entry already exists
}
}
You should use ExecuteScalar when the return value of your query is only a single row with a single column. Of course the OleDbCommand that has parameters placeholders in its command text needs to have also a corresponding Parameters collection
using (OleDbConnection con = new OleDbConnection(constr))
using (OleDbCommand com = new OleDbCommand("SELECT COUNT(*) FROM StudentList WHERE [FName] = #FName AND [LName] = #LName", con))
{
con.Open();
com.Parameters.AddWithValue("#FName", txtFirstName.Text);
com.Parameters.AddWithValue("#LName", txtLastName.Text);
int count = Convert.ToInt32(com.ExecuteScalar());
if(count == 0)
{
... record doesn't exist
}
else
{
... you have got count records
}
}
However let me say that this logic is rather weak. What happen if two students have the same First and Last name? What happen if someone mistype the name?. I think that you should require something more unique. Like a SSN or another ID provided by your school. (A Student Number or something alike)
if (txtYear.Text != "")
{
cmd = new SqlCommand("Select YearName from Year where YearName='" + txtYear.Text + "'", ConnOpen());
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(ds);
int i = ds.Tables[0].Rows.Count;
if (i > 0)
{
MessageBox.Show("Duplicate Values are not valid!!!");
}
else
{
if (Classes.ClassDatabaseConnection.UserMessage("Are you srue you want to Add this Year!!!", "Confirm Updation") == true)
{
string insert = "insert into Year(YearName) values('" + txtYear.Text + "')";
int result = sqlrep.ExecuteNonQuery(insert);
if (result > 0)
{
System.Windows.Forms.MessageBox.Show("Year Added Successfully.", "Information", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Information);
}
}
dataLoad();
}
}

Adding to a sql integer column using C#

I am trying to update a SQL table from my C# backend, but it never successfully executes; mainServiceButton is a pre-existing value in the linkName column. Here is what I have so far:
conn.Open();
string qry = "UPDATE clickStream SET clickCount = (clickCount + 1) WHERE linkName = mainServiceButton";
SqlCommand cmd = new SqlCommand(qry, conn);
try
{
cmd.ExecuteScalar();
}
catch
{
MessageBox.Show("not executed");
}
conn.Close();
This is how the table was created:
CREATE TABLE clickStream(
click_ID int identity(1,1),
linkName nvarchar(50) not null,
clickCount int,
PRIMARY KEY(click_ID));
The desired result is to increase the clickCount by 1 every time a link(linkName) is clicked on. Any Suggestions?
MessageBox.Show("not executed"); is not going to help you much except to obscure the details of the error: you need to instead output the details of the caught exception to understand what happened.
Addressing this and other suggestions made in comments...
mainServiceButton nakedly inline in the SQL text not possibly being what you want
a SqlParameter being warranted to accept a value for the WHERE sanely
ExecuteNonQuery() instead of ExecuteScalar() being the right call
..., see what sort of mileage you get with this instead:
conn.Open();
string qry = "UPDATE clickStream SET clickCount = (clickCount + 1) WHERE linkName = #linkName";
SqlCommand cmd = new SqlCommand(qry, conn);
// Use a SqlParameter to correct an error in the posted code and do so safely.
cmd.Parameters.Add(new SqlParameter("#linkName", "mainServiceButton"));
try
{
cmd.ExecuteNonQuery(); // not ExecuteScalar()
}
catch (SqlException sex)
{
// Output the exception message and stack trace.
MessageBox.Show(sex.ToString());
}
conn.Close();
Try the below, not tested so you may need to fix minor bugs:
conn.Open();
string qry = "UPDATE clickStream SET clickCount = (clickCount + 1) WHERE linkName = 'mainServiceButton';SELECT ##ROWCOUNT;";
SqlCommand cmd = new SqlCommand(qry, conn);
try
{
int rowsAffected = (int)cmd.ExecuteScalar();
if (rowsAffected != 1)
throw new ApplicationException("Rows affected should be 1, " + rowsAffected + " were affected.");
}
catch (Exception ex)
{
MessageBox.Show("Not executed successfully, exception: " + ex.ToString());
}
conn.Close();

how to solve this SQL and foreign language issue?

I wrote this procedure in a site. it take a string as input parameter(user name) and looks into the related table to find out it's record and return the "ID" field as output of procedure.
this work fine but there's one (major) problem, which is when it take a input in other English language, it can't find the target record and return "-1" as output.
The visitors use Persian language and i observed it in my SQLserver. The collation is "Persian_100_CI_AI" and my string fields are "nvarchar".
what should i do to solve this problem?
i'm using SQL-Server 2008.
thanks a lot
protected int GetThisUserID(string uname)
{
string returnvalue = "";
int returnintegervalue = -1;
SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["OldEagleConnectionString"].ToString());
try
{
//SqlCommand command = new SqlCommand("SELECT [ID] FROM [Customers] WHERE ([Uname] = '" + User.Identity.Name.ToString() + "'", connection);
//SqlCommand command = new SqlCommand("SELECT * FROM [Customers] WHERE ([Uname] = '" + User.Identity.Name.ToString() + "')", connection);
SqlCommand command = new SqlCommand("SELECT * FROM [Customers] WHERE ([Uname] = '" + uname + "')", connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
returnvalue = reader["ID"].ToString();
returnintegervalue = Int32.Parse(returnvalue);
}
}
}
catch (SqlException ex)
{
Response.Write(ex.Message.ToString());
returnvalue = ex.Message.ToString();
}
finally
{
connection.Close();
SqlConnection.ClearPool(connection);
}
return returnintegervalue;
}
I hate to answer my own question but here it is:
have to add a N in select command, just like this:
SqlCommand command = new SqlCommand("SELECT * FROM [Customers] WHERE ([Uname] = N'" + uname + "')", connection);
problem solved!
Without the N, the string is taken to be a varchar, and the conversion loses characters outside of that supported by the varchar encoding of the database.

Categories