I have a DataGridView(DGV) linked to a SQlite database. I want to update some info on the DGV. So, I have a context menu that lets me change one column and update the DB as well. I want to have the ability to select multiple rows and edit as well. For ex: if i select five rows and change the type from alarms to errors ; the change is reflected in the DGV and then when i look into the database , the change isnt reflected. Only one row is updated.
My code snippet is below
foreach (DataGridViewRow r in dataGridView1.SelectedRows)
{
SQLiteTransaction SQLiteTrans = connection.BeginTransaction();
SQLiteCommand cmd = connection.CreateCommand();
MessageBox.Show(r.ToString());
if (r.Cells["typeDataGridViewTextBoxColumn"].Value.ToString().Contains("#") == false)
{
r.Cells["typeDataGridViewTextBoxColumn"].Value = r.Cells["typeDataGridViewTextBoxColumn"].Value.ToString() + " # " + max;
}
else
{
r.Cells["typeDataGridViewTextBoxColumn"].Value = r.Cells["typeDataGridViewTextBoxColumn"].Value.ToString().Substring(0, r.Cells["typeDataGridViewTextBoxColumn"].Value.ToString().IndexOf("#")) + "# " + max;
}
string querytext = "Update LogDatabase set Type = \"" + r.Cells["typeDataGridViewTextBoxColumn"].Value + "\" where HashKey = \"" + r.Cells["hashKeyDataGridViewTextBoxColumn"].Value.ToString() + "\"";
cmd.CommandText = querytext;
cmd.ExecuteNonQuery();
SQLiteTrans.Commit();
}
I dont have too much experience with SQL. So, im not sure if something is wrong with how ive updated the database!
What do i have to edit to make sure all the rows are updated in the DB as well?!
Help appreciated.
Edit: Tried checking the query before its sent.
When i try editing multiple rows in the DGV without sorting the DGV under any column it works and updates all the rows simultaneously... But When I try to sort them based on "Type" and then edit the rows, the same query is passed ! :| (Hash Key doesnt change)
Its like, the one row keeps moving up the list of rows and is always the row r in the for loop.
Edit 2: Its definitely a problem with the rows of the DGV
Everytime I sort the DGV and then try to edit the fields, the queries have hashkey values different from the once that i selected. Its like the row ids are changed completely after one update. It looks like the DGV automatically sorts once one row is updated !
Is there a way to disable this???!
It looks like you weren't increasing max counter.
foreach (DataGridViewRow row in dataGridView1.SelectedRows)
{
using (SQLiteTransaction SQLiteTrans = connection.BeginTransaction())
{
SQLiteCommand cmd = connection.CreateCommand();
MessageBox.Show(row.ToString());
var txtValue = row.Cells["typeDataGridViewTextBoxColumn"].Value;
if (txtValue.Contains("#"))
{
txtValue = String.Format("{0} # {1}", txtValue, max);
}else
{
txtValue = txtValue.SubString(0, txtValue.IndexOf("#")) + "# " + max.ToString();
}
string querytext = "Update LogDatabase set Type = #type where HashKey = #key";
//Create your SqlParameters here!
cmd.CommandText = querytext;
cmd.ExecuteNonQuery();
SQLiteTrans.Commit();
max++; //You weren't increasing your counter!!
}
}
Your problem is that you are using double quotes in your SQL query to delimit your string values. Replace them for single quotes:
string querytext = "Update LogDatabase set Type = '" +
r.Cells["typeDataGridViewTextBoxColumn"].Value +
"' where HashKey = '" +
r.Cells["hashKeyDataGridViewTextBoxColumn"].Value.ToString() +
"'";
Also, beware of SQL Injection. Your code is not dealing with that.
Related
I would like to update my mySQL table from a DatagridView with DataGridViewCheckBoxColumns and display it back to my forms. However, my current code checks all rows even if only a single CheckBoxColumn has been checked. Checked or unchecked rows should be both updated so I'm not sure if I still have to add condition if DataGridViewCheckBoxColumns are checked.
foreach (DataGridViewRow row in datagridFamMedHistory.Rows)
{
command.Parameters.Clear();
famMedHistorytype = datagridFamMedHistory.Rows[0].Cells["colType"].Value.ToString();
command.CommandText = #"UPDATE familymedhistory SET paternal = #paternal, maternal = #maternal
WHERE patientid = '" + patientid + "' AND type = '" + famMedHistorytype + "'";
command.Parameters.AddWithValue("#paternal", row.Cells["colPaternal"].Value);
command.Parameters.AddWithValue("#maternal", row.Cells["colMaternal"].Value);
connect.Open();
command.ExecuteNonQuery();
connect.Close();
}
I think I'm missing something, but I can't seem to figured it out.
did you debugged your code?
You are still selecting row 0 in your loop
change :
famMedHistorytype = datagridFamMedHistory.Rows[0].Cells["colType"].Value.ToString();
to :
famMedHistorytype = row.Cells["Column1"].Value.ToString();
Also As collegue wrote in comment, do not open and close connection in loop.. my eyes are bleeding
I am creating string function which checks duplicate record before inserting or updating a record but I have a condition with it. Before giving conditions, I have a table called Products (name, description, type, isActive, InsertedDate, UpdatedDate). Isenabled is in bit datatype (0 or 1). And InsertedDate, UpdatedDate are auto generated.
In isActive column
0 means disable
1 means enable
Before inserting (or even updating), check whether name is unique but if name exist more than one then,
My conditions
Check whether product is isActive = 1 then while inserting data should display message "Product exist in the table."
Check whether product is isActive = 0 then while inserting data should display message "Product exist but it is disabled."
Else Insert/Update the data.
Below function only check whether record exist or not and return message accordingly.
Question: How can I have return proper message regardless I am checking above query for inserting or updating a record and it goes over my requirement. As Top 1 can help me to insert new record checking if name is unique and it will return empty but if I am updating row with its own keeping name as it is and changing other column which is description. And when I update that I am receiving message "Record exist in the table" which it should not give me and should updating without message. So how can I make this query check for both the method inserting and updating record.
Here is what I have tried:
private string GetName(string name, int id)
{
using (var connection = connection string)
using (var command = new SqlCommand())
{
command.Connection = connection;
command.CommandText =
#"DECLARE #Enabled INT; " +
#"SET #Enabled = " +
#"( " +
#"SELECT TOP 2 p.isActive " +
#"FROM dbo.[product] p WITH (nolock) " +
#"WHERE p.name = #name " +
#"); " +
#"SELECT Msg = CONVERT( VARCHAR(32), " +
#"CASE " +
#"WHEN #Enabled = 0 " +
#"THEN 'Record is disabled' " +
#"WHEN #Enabled = 2 " +
#"THEN 'Record exist in the table' " +
#"ELSE ''";
#"END);";
command.Parameters.AddWithValue("name", name);
command.CommandTimeout = 100;
connection.Open();
command.ExecuteNonQuery();
string message = (string)command.ExecuteScalar();
connection.Close();
return message;
}
}
return string.Empty;
}
Note My query might be wrong. If you do not understand my query then please go over to what I am doing before inserting or updating record and accordingly I am expecting to have a query. Also please don't worry about Insert or update query I have a different method which takes care of it. Also if you have any solution which can help me to solve my probkem ten I would really appreciate that.
Summery
First check duplicate record exist or not (Means check all names are unique).
If name exist more than 1 then check isActive is 0 or 1 and accordingly sends the message which I am showing in my query.
FYI: I know I can do it in Stored Procedure but this is like a requirement to do it with command parameter.
Also if you guys think tha this post does not have consistant, please let me know instead of downgrading or flagging it.
My issue is that everytime I try to update in my CMS, it simply updates EVERY column / row.
For example:
I update Test 1 -> Test 2
Meanwhile I have Test 4
But then Test 4 -> Test 2 due to I changed Test 1 to 2 it simply changes that aswell.
They still work by ID correctly, and when I delete them, they delete individually, so the only function that is overlapping with everything is update.
I will now post my code (this is what I have learned, do not comment on security or w/e) simply need this issue fixed so it only updates the selected ID row.
First:
public DataRow GetById(string ID)
{
strSQL = "SELECT ID, clnOverskrift, clnTekst "
+ "FROM tblForside "
+ "WHERE ID=#ID";
objCMD = new MySqlCommand(strSQL);
objCMD.Parameters.AddWithValue("#ID", ID);
return objData.GetData(objCMD, objCon).Rows[0];
}
public void Update(PropertyForside Pro)
{
strSQL = "UPDATE tblForside SET "
+ " clnOverskrift=#Overskrift, clnTekst=#Tekst ";
objCMD = new MySqlCommand(strSQL);
objCMD.Parameters.AddWithValue("#Overskrift", Pro.Overskrift);
objCMD.Parameters.AddWithValue("#Tekst", Pro.Tekst);
objData.ModifyData(objCMD, objCon);
}
I will use both GetById and Update thats why I included both.
if you need to know more in this "factory" i will post it.
Here i get it:
FactoryForside fac = new FactoryForside();
PropertyForside Pro = new PropertyForside();
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
DataRow dr = fac.GetById(Request.QueryString["ID"]);
txtOverskrift.InnerText = dr["clnOverskrift"].ToString();
txtText.InnerText = dr["clnTekst"].ToString();
}
}
protected void btnGem_Click(object sender, EventArgs e)
{
Pro.Overskrift = txtOverskrift.InnerText;
Pro.Tekst = txtText.InnerText;
Pro.ID = int.Parse(Request.QueryString["ID"]);
fac.Update(Pro);
Response.Redirect("RedigerForside.aspx");
}
I use InnerText to use TextAreas with NiceEdit.
Adding new ones work, and deleting as mentioned before - only this updating thing not working correctly.
It displays ID correctly "EditForside.aspx?id=13" in the browser, but it seems to select every other ID aswell
Hope you can help me.
Your UPDATE statement has to include a WHERE condition - the same you use in your select. Then it will update only that particular row. Without a WHERE it updates every row in the table.
Documentation: http://dev.mysql.com/doc/refman/5.0/en/update.html
The reason might be because you have not provided the where condition in your update clause. So if you dont provide a where condition in your update statement it would end up updating every row of your table.
Try something like this:
strSQL = "UPDATE tblForside SET "
+ " clnOverskrift=#Overskrift, clnTekst=#Tekst "
+ " WHERE ID=#ID";
You need to provide a WHERE clause in your update statement. E.g.
strSQL = "UPDATE tblForside SET "
+ " clnOverskrift=#Overskrift, clnTekst=#Tekst "
+ " WHERE ID=#ID";
This limits which rows will be updated.
I have a datatable that may have 1000 or so rows in it. I need to go thru the datatable row by row, get the value of a column, run a query (Access 2007 DB) and update the datatable with the result. Here's what I have so far, which works:
String FilePath = "c:\\MyDB.accdb";
string QueryString = "SELECT MDDB.NDC, MDDB.NDC_DESC "
+ "FROM MDDB_MASTER AS MDDB WHERE MDDB.NDC = #NDC";
OleDbConnection strAccessConn = new OleDbConnection(string.Format("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + FilePath));
strAccessConn.Open();
OleDbDataReader reader = null;
int rowcount = InputTable.Rows.Count; //InputTable is the datatable
int count = 0;
while (count < rowcount)
{
string NDC = InputTable.Rows[count]["NDC"].ToString();
//NDC is a column in InputTable
OleDbCommand cmd = new OleDbCommand(QueryString, strAccessConn);
cmd.Parameters.Add("#NDC", OleDbType.VarChar).Value = NDC;
reader = cmd.ExecuteReader();
while (reader.Read())
{
//update the NDCDESC column with the query result
//the query should only return 1 line
dataSet1.Tables["InputTable"].Rows[count]["NDCDESC"] = reader.GetValue(1).ToString();
}
dataGridView1.Refresh();
count++;
}
strAccessConn.Close();
However this seems very inefficient since the query needs to run one time for each row in the datatable. Is there a better way?
You're thinking of an update query. You don't actually have to go over every row one by one. SQL is a set based language, so you only have to write a single statement that it should do for all rows.
Do this:
1) Create > Query Design
2) Close the dialog that selects tables
3) Make sure you're in sql mode (top left corner)
4) Paste this:
UPDATE INPUTTABLE
INNER JOIN MDDB_MASTER ON INPUTTABLE.NDC = MDDB_MASTER.NDC
SET INPUTTABLE.NDCDESC = [MDDB_MASTER].[NDC_DESC];
5) Switch to design mode to see what happens. You may have to correct Input table, I couldn't find it's name. I'm assuming they;re both in the same database.
You'll see the query type is now an update query.
You can run this text through cmd.ExecuteNonQuery(sql) and the whole thing should run very quickly. If it doesn't you'll need an index on one of the tables;
THis works by joining the two table on NDC and then copying the NDC_DESC over from MDDB_MASTER to the inputtable.
I missed the part about InputTable coming from Excel.
For better speed, instead of executing the query in Access over and over, you can get all rows from MDDB_MASTER into a datatable in one select statement:
SELECT MDDB.NDC, MDDB.NDC_DESC FROM MDDB_MASTER
And then use the DataTable.Select method to filter the right row.
mddb_master.Select("NDC = '" + NDC +'")
This will be done in memory and should be much faster than all the round trips you have now. Especially over the network these round trips are expensive. 225k rows should be only a few MB (roughly a JPEG image) so that shouldn't be an issue.
You could use the "IN" clause to build a bigger query such as:
string QueryString = "SELECT MDDB.NDC, MDDB.NDC_DESC "
+ "FROM MDDB_MASTER AS MDDB WHERE MDDB.NDC IN (";
int rowcount = InputTable.Rows.Count; //InputTable is the datatable
int count = 0;
while (count < rowcount)
{
string NDC = InputTable.Rows[count]["NDC"].ToString();
QueryString += (count == 0 ? "" : ",") + "'" + NDC + "'";
}
QueryString += ")";
You can optimize that with StringBuilders since that could be a lot of strings but that's a job for you. :)
Then in a single query, you would get all the NDC descriptions you need and avoid performing 1000 queries. You would then roll through the reader, find values in the InputTable, and update them. Of course, in this case, you're looping through the InputTable multiple times but it might be a better option. Especially if yor InputTable could hold duplicate NDC values.
Also, note that you have a OleDbDataReader leak in your code. You keep reassigning the reader reference to a new instance of a reader before disposing of the old reader. Same with commands. You keep instantiating a new command but are not disposing of it properly.
I select the DropDownList value to insert in query but the value remains blank in query and due to empty value in where condition not any result outcome. I do with different tricks but remain empty
if (chkBoxChanl.Checked)
{
sql += " and channelName = '" + ddlChannel.Text + "' ";
}
if (chkBoxDate.Checked)
{
sql += " and transmissionDate_ between '" + tbFrom.Text + "' and '" + tbTo.Text + "'";
}
if (chkBoxProgrm.Checked)
{
sql += " and programName ='" + ddlProgram.Text + "'";
}
if (chkBoxParty.Checked)
{
sql += " and partiesName like '%" + ddlParty.SelectedValue + "%'";
}
if (chkBoxPerson.Checked)
{
sql += " and personsName like '%" + ddlPerson.SelectedItem + "%'";
}
if (chkBoxProvince.Checked)
{
sql += " and ProvinceName like '%" + ddlProvince.SelectedItem + "%'";
}
if (chkBoxCity.Checked)
{
sql += " and CityName like '%" + ddlCity.Text + "%'";
}
Like
ddlProgram.Text
ddlProvince.SelectedItem
ddlPerson.SelectedValue
selected DropDownList value is shown empty in query.
What can I do to add the selected value in query? Please help me!
I check that when I select the dropdownist values which come on first load then 2md time after press search button dropdownlist values empty and when I press search button it first run Page_Load function and if(!IspostBack) is execute then all dropdownlist selected values become empty which cause to empty values in where clause. Now I want that when I press search button dropdownlist values remain loaded which will resolve the issue to become enpty dropdownlist values. Please guide me further
First of all: you shouldn't concatenate parameters to queries in this way. You expose yourself to SQL injection attacks.
Sorry, new to stackoverflow. Didn't see the comment button
and
programName =' mytext' OR 1 = 1;
DROP Database
Comment anything else.
You cannot concatenate your input field's values directly in your sql query. It makes your system vulnerable to Sql Injection. You should at least encode what you are retrieving from these fields before running such sql query. It is very important that you read this before going ahead.
After reading the above carefully, you can get the value of the selected item on your dropdown. You do this:
yourDropDown.SelectedItem.Value
If it does not return a value, that's probably because you didn't set any value in your dropdown. Remember to set it according to your datasource:
yourDropDown.DataValueField = "TheSourceFieldContainingTheValue";
Build your sql query something like this :
public DataSet ExecuteDataSet(string text, SqlParameter[] paramList)
{
using (SqlCommand sqlCommand = new SqlCommand(text, sqlConnection))
{
if (paramList != null)
{
foreach (var param in paramList)
{
sqlCommand.Parameters.Add(param);
}
}
SqlDataAdapter dataAdapter = new SqlDataAdapter(sqlCommand);
DataSet dataSet=new DataSet();
dataAdapter.Fill(dataSet);
return dataSet;
}
}