I am trying to delete data from a Database AND the DataGridViewer using Winforms on Visual Studio. The way I am doing this is selecting a cell, and based on where that cell is, that row will be deleted. The selected row will read two strings and one date. I've tested the two strings and they work perfectly when deleting data. When it comes to the date, it doesn't seem to work for me, I keep getting an error. The error message will be attached as an image and the code will be below. I am fairly new to C# and SQL, just to put that out there.
private void delete_Click(object sender, EventArgs e)
{
foreach (DataGridViewCell theCell in daily_log.SelectedCells)
{
if (theCell.Selected)
{
string eid = daily_log[0, theCell.RowIndex].Value.ToString();
string aid = daily_log[4, theCell.RowIndex].Value.ToString();
DateTime dt = Convert.ToDateTime(daily_log[5, theCell.RowIndex].Value);
try
{
connection.Open();
using (OleDbCommand cmd = new OleDbCommand("DELETE FROM DailyLog WHERE EmployeeID='" + eid + "' AND ActivityID = '" + aid + "' AND Date = '" + dt.Date + "'", connection))
{
cmd.ExecuteNonQuery();
}
connection.Close();
daily_log.Rows.RemoveAt(theCell.RowIndex);
}
catch (Exception ex)
{
MessageBox.Show("Err: " + ex);
}
}
}
}
Is this a conversion error? And if so, how would I fix this?
You could try to use OledbParameter to delete data from access database.
Here is a code example you can refer to.
OleDbConnection conn = new OleDbConnection("connstr");
private void button1_Click(object sender, EventArgs e)
{
foreach (DataGridViewCell theCell in dataGridView1.SelectedCells)
{
if (theCell.Selected)
{
string id = dataGridView1[0, theCell.RowIndex].Value.ToString();
string aid = dataGridView1[1, theCell.RowIndex].Value.ToString();
DateTime dt = Convert.ToDateTime(dataGridView1[2, theCell.RowIndex].Value);
try
{
conn.Open();
string sql = "delete from DailyLog where ID=#ID AND AID=#AID AND Date=#Date";
using (OleDbCommand cmd = new OleDbCommand(sql, conn))
{
cmd.Parameters.AddWithValue("#ID", id);
cmd.Parameters.AddWithValue("#AID", aid);
cmd.Parameters.AddWithValue("#Date", dt);
cmd.ExecuteNonQuery();
}
dataGridView1.Rows.RemoveAt(theCell.RowIndex);
}
catch (Exception ex)
{
MessageBox.Show("Err: " + ex);
}
}
}
conn.Close();
}
private void Form1_Load(object sender, EventArgs e)
{
conn.Open();
string query = "select * from DailyLog";
OleDbDataAdapter da = new OleDbDataAdapter(query, conn);
OleDbCommandBuilder builder = new OleDbCommandBuilder(da);
var ds = new DataSet();
da.Fill(ds);
dataGridView1.DataSource = ds.Tables[0];
conn.Close();
}
Result:
Your Ids are probably numeric, and Date is a reserved word, so try with:
"DELETE FROM DailyLog WHERE EmployeeID = " + eid + " AND ActivityID = " + aid + " AND [Date] = #" + dt.Date.ToString("yyyy'/'MM'/dd") + "#"
That said, go for using parameters.
{
Can anyone help me on how to avoid getting duplicated output on DataGridView. Here is the image Before change and the image After add/edit or delete.
Here is the loader for my DataGridView:
private DataTable data()
{
using (OleDbConnection con = new OleDbConnection(inventorydb))
{
using (OleDbCommand com = new OleDbCommand("Select * FROM Items",con))
{
con.Open();
OleDbDataReader reader = com.ExecuteReader();
items.Load(reader);
}
}
return items;
}
void reset()
{
connect.Close();
connect.ConnectionString = inventorydb;
connect.Open();
dataGridView1.DataSource = null;
dataGridView1.Update();
dataGridView1.Refresh();
dataGridView1.DataSource = data();
}
Add and save changes:
private void save_Click(object sender, EventArgs e)
{
if (mode == "a")
{
connect.Close();
connect.ConnectionString = inventorydb;
connect.Open();
sqlcommand.CommandText = "INSERT INTO Items (SerialID, Brand_Name, Item_Name,Item_Date) VALUES ('" + txtserial.Text + "','" + txtbrand.Text + "', '" + txtitem.Text + "', '" + date + "') ";
sqlcommand.Connection = connect;
OleDbDataReader reader = sqlcommand.ExecuteReader();
MessageBox.Show("Record(s) Saved", "Sample");
}
connect.Close();
reset();
}
DataTable.Load adds result to the existing rows by default. So if you need to just have latest records, before calling DataTable.Load, you should clear the DataTable, otherwise the new result will be merged with existing rows.
So with your items variable which is DataTable, you can use either of these options:
items= new DataTable();
or
items.Clear();
items.AcceptChanges();
DataTable.Load
Fills a DataTable with values from a data source using the supplied
IDataReader. If the DataTable already contains rows, the incoming
data from the data source is merged with the existing rows.
I'm trying to a simple insert list of rows from a DataGridView to a database.
I have made a checkedbox that upon checked, the item will be added to the DataGridView. Now i'm attempting to do the INSERT part. This what I have come up so far:
try
{
string strAppointment = "SELECT appointmentID FROM APPOINTMENT WHERE appointmentID=#searchappointmentID";
SqlCommand cmdAppointment = new SqlCommand(strAppointment, connection);
cmdAppointment.Parameters.AddWithValue("#searchappointmentID", txtAppointmentID.Text);
connection.Open();
for (int i = 0; i < dataPrescription.Rows.Count; i++)
{
string firstColumn = dataPrescription[0, dataPrescription.CurrentCell.RowIndex].Value.ToString();
string strMedications = "SELECT medicationID FROM MEDICATION WHERE medicationName= ('" + firstColumn + "')";
SqlCommand cmdMedications = new SqlCommand(strMedications, connection);
SqlDataReader readMedications = cmdMedications.ExecuteReader();
if (readMedications.Read())
{
string getDrugID = readMedications["medicationID"].ToString();
string strPrescriptions = "INSERT INTO PRESCRIPTION (appointmentID, medicationID, quantity) " +
"VALUES (#insertAppointment, "
+ getDrugID + ", "
+ dataPrescription.Rows[i].Cells["columnQuantity"].Value + ");";
SqlCommand cmdPrescriptions = new SqlCommand(strPrescriptions, connection);
cmdPrescriptions.Parameters.AddWithValue("#insertAppointment", txtAppointmentID.Text);
prescriptionsResult = cmdAppointment.ExecuteNonQuery();
}
readMedications.Close();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error");
}
finally
{
connection.Close();
}
Right now it giving me this error: "There is already an open DataReader associated with the command which must be closed first". I don't know what I've done wrong
Try this: (initialize the datareader)
for (int i = 0; i < dataPrescription.Rows.Count; i++)
{
string firstColumn = dataPrescription[0, dataPrescription.CurrentCell.RowIndex].Value.ToString();
string strMedications = "SELECT medicationID FROM MEDICATION WHERE medicationName= ('" + firstColumn + "')";
SqlCommand cmdMedications = new SqlCommand(strMedications, connection);
SqlDataReader dr = new SqlDataReader(); //Insert this line in your code
SqlDataReader readMedications = cmdMedications.ExecuteReader();
It looks like you're trying to execute a command using a connection that's occupied with the reader, and I would look at that as being the problem. Instead of trying to execute the insert inside the reader, try reading the data to a collection and closing the reader, then iterating the connection to make you're updates.
I am struggling for updating record/columnvalue in MS-ACCESS database... help would be appreciated a lot..!
I am displaying a list of partnumbers retrieved from a table in Ms-access using Datagridview in which I am supposed to update/change partnumber. ( 'partno' is 3rd column of my datagridview.)
But I am unable to Update a single record in database..no exceptions.. everything is going fine.!
But no rows are effected!
Here is my code:
private void UpdateDetails_Click(object sender, EventArgs e)
{
try
{
con = new OleDbConnection();
con.ConnectionString = Helper.MyConnectionString;
con.Open();
for (int i = 0; i <= datagridview1.Rows.Count-1; i++)
{
int j = i + 1; // j is the serial number corresponding to partnumber
string partno = dgv1.Rows[i].Cells[2].Value.ToString(); //getting part number from Datagridview
String partquery = "";
if (partno == null || partno == "") //checking whether part number updated or not
{
partquery = "update Vendor SET PartNo=NULL where Vendor.Sno=" + j + " ";
}
else
partquery = "update Vendor SET PartNo='" + partno + "' where Vendor.Sno=" + j + " ";
//Vendor is the table name containg 'partno' list
cmd = new OleDbCommand();
cmd.Connection = con;
cmd.CommandType = CommandType.Text;
cmd.CommandText = partquery;
cmd.ExecuteNonQuery();
}
}
catch(Exception ex)
{
//exception handler
}
}
As #Soner suggested you should use parameters. Something like this.
Modified the code did you do something like this?
private void UpdateDetails_Click(object sender, EventArgs e)
{
try
{
con = new OleDbConnection();
con.ConnectionString = Helper.MyConnectionString;
con.Open();
for (int i = 0; i <= datagridview1.Rows.Count - 1; i++)
{
int j = i + 1; // j is the serial number corresponding to partnumber
string partno = dgv1.Rows[i].Cells[2].Value.ToString(); //getting part number from Datagridview
//String partquery = "";
//if (partno == null || partno == "") //checking whether part number updated or not
//{
// partquery = "update Vendor SET PartNo=NULL where Vendor.Sno=" + j + " ";
//}
//else
// partquery = "update Vendor SET PartNo='" + partno + "' where Vendor.Sno=" + j + " ";
OleDbCommand cmd = new System.Data.OleDb.OleDbCommand("update Vendor SET PartNo='#partno' where Vendor.Sno=#vndid");
OleDbParameter parameter = new System.Data.OleDb.OleDbParameter("#partno", partno);
cmd.Parameters.Add(parameter);
parameter = new System.Data.OleDb.OleDbParameter("#vndid", j);
cmd.Parameters.Add(parameter);
cmd.Connection = con;
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
}
}
catch (Exception ex)
{
//exception handler
}
}
I have imported data from some Excel file and I have saved it into a datatable. Now I'd like to save this information in my SQL Server database.
I saw a lot of information on the web but I cannot understand it:
Someone said insert line by line another suggested bulk update... etc: what it better?
Should I use OLE or SQL Server objects (like dataAdapter or connection)?
My need is to read the employee weekly hours report, from his Excel file and save it to a database table where all the reports are saved (updating the db with new records every week).
The Excel file contains reports only for the current week.
Create a User-Defined TableType in your database:
CREATE TYPE [dbo].[MyTableType] AS TABLE(
[Id] int NOT NULL,
[Name] [nvarchar](128) NULL
)
and define a parameter in your Stored Procedure:
CREATE PROCEDURE [dbo].[InsertTable]
#myTableType MyTableType readonly
AS
BEGIN
insert into [dbo].Records select * from #myTableType
END
and send your DataTable directly to sql server:
using (var command = new SqlCommand("InsertTable") {CommandType = CommandType.StoredProcedure})
{
var dt = new DataTable(); //create your own data table
command.Parameters.Add(new SqlParameter("#myTableType", dt));
SqlHelper.Exec(command);
}
To edit the values inside stored-procedure, you can declare a local variable with the same type and insert input table into it:
DECLARE #modifiableTableType MyTableType
INSERT INTO #modifiableTableType SELECT * FROM #myTableType
Then, you can edit #modifiableTableType:
UPDATE #modifiableTableType SET [Name] = 'new value'
If it's the first time for you to save your datatable
Do this (using bulk copy). Assure there are no PK/FK constraint
SqlBulkCopy bulkcopy = new SqlBulkCopy(myConnection);
//I assume you have created the table previously
//Someone else here already showed how
bulkcopy.DestinationTableName = table.TableName;
try
{
bulkcopy.WriteToServer(table);
}
catch(Exception e)
{
messagebox.show(e.message);
}
Now since you already have a basic record. And you just want to check new record with the existing one. You can simply do this.
This will basically take existing table from database
DataTable Table = new DataTable();
SqlConnection Connection = new SqlConnection("ConnectionString");
//I assume you know better what is your connection string
SqlDataAdapter adapter = new SqlDataAdapter("Select * from " + TableName, Connection);
adapter.Fill(Table);
Then pass this table to this function
public DataTable CompareDataTables(DataTable first, DataTable second)
{
first.TableName = "FirstTable";
second.TableName = "SecondTable";
DataTable table = new DataTable("Difference");
try
{
using (DataSet ds = new DataSet())
{
ds.Tables.AddRange(new DataTable[] { first.Copy(), second.Copy() });
DataColumn[] firstcolumns = new DataColumn[ds.Tables[0].Columns.Count];
for (int i = 0; i < firstcolumns.Length; i++)
{
firstcolumns[i] = ds.Tables[0].Columns[i];
}
DataColumn[] secondcolumns = new DataColumn[ds.Table[1].Columns.Count];
for (int i = 0; i < secondcolumns.Length; i++)
{
secondcolumns[i] = ds.Tables[1].Columns[i];
}
DataRelation r = new DataRelation(string.Empty, firstcolumns, secondcolumns, false);
ds.Relations.Add(r);
for (int i = 0; i < first.Columns.Count; i++)
{
table.Columns.Add(first.Columns[i].ColumnName, first.Columns[i].DataType);
}
table.BeginLoadData();
foreach (DataRow parentrow in ds.Tables[0].Rows)
{
DataRow[] childrows = parentrow.GetChildRows(r);
if (childrows == null || childrows.Length == 0)
table.LoadDataRow(parentrow.ItemArray, true);
}
table.EndLoadData();
}
}
catch (Exception ex)
{
throw ex;
}
return table;
}
This will return a new DataTable with the changed rows updated. Please ensure you call the function correctly. The DataTable first is supposed to be the latest.
Then repeat the bulkcopy function all over again with this fresh datatable.
I am giving a very simple code, which i used in my solution (I have the same problem statement as yours)
SqlConnection con = connection string ;
//new SqlConnection("Data Source=.;uid=sa;pwd=sa123;database=Example1");
con.Open();
string sql = "Create Table abcd (";
foreach (DataColumn column in dt.Columns)
{
sql += "[" + column.ColumnName + "] " + "nvarchar(50)" + ",";
}
sql = sql.TrimEnd(new char[] { ',' }) + ")";
SqlCommand cmd = new SqlCommand(sql, con);
SqlDataAdapter da = new SqlDataAdapter(cmd);
cmd.ExecuteNonQuery();
using (var adapter = new SqlDataAdapter("SELECT * FROM abcd", con))
using(var builder = new SqlCommandBuilder(adapter))
{
adapter.InsertCommand = builder.GetInsertCommand();
adapter.Update(dt);
// adapter.Update(ds.Tables[0]); (Incase u have a data-set)
}
con.Close();
I have given a predefined table-name as "abcd" (you must take care that a table by this name doesn't exist in your database).
Please vote my answer if it works for you!!!! :)
I would suggest you go for bulk insert as suggested in this article :
Bulk Insertion of Data Using C# DataTable and SQL server OpenXML function
public bool BulkCopy(ExcelToSqlBo objExcelToSqlBo, DataTable dt, SqlConnection conn, SqlTransaction tx)
{
int check = 0;
bool result = false;
string getInsert = "";
try
{
if (dt.Rows.Count > 0)
{
foreach (DataRow dr in dt.Rows)
{
if (dr != null)
{
if (check == 0)
{
getInsert = "INSERT INTO [tblTemp]([firstName],[lastName],[Father],[Mother],[Category]" +
",[sub_1],[sub_LG2])"+
" select '" + dr[0].ToString() + "','" + dr[1].ToString() + "','" + dr[2].ToString() + "','" + dr[3].ToString() + "','" + dr[4].ToString().Trim() + "','" + dr[5].ToString().Trim() + "','" + dr[6].ToString();
check += 1;
}
else
{
getInsert += " UNION ALL ";
getInsert += " select '" + dr[0].ToString() + "','" + dr[1].ToString() + "','" + dr[2].ToString() + "','" + dr[3].ToString() + "','" + dr[4].ToString().Trim() + "','" + dr[5].ToString().Trim() + "','" + dr[6].ToString() ;
check++;
}
}
}
result = common.ExecuteNonQuery(getInsert, DatabasesName, conn, tx);
}
else
{
throw new Exception("No row for insertion");
}
dt.Dispose();
}
catch (Exception ex)
{
dt.Dispose();
throw new Exception("Please attach file in Proper format.");
}
return result;
}
//best way to deal with this is sqlbulkcopy
//but if you dont like it you can do it like this
//read current sql table in an adapter
//add rows of datatable , I have mentioned a simple way of it
//and finally updating changes
Dim cnn As New SqlConnection("connection string")
cnn.Open()
Dim cmd As New SqlCommand("select * from sql_server_table", cnn)
Dim da As New SqlDataAdapter(cmd)
Dim ds As New DataSet()
da.Fill(ds, "sql_server_table")
Dim cb As New SqlCommandBuilder(da)
//for each datatable row
ds.Tables("sql_server_table").Rows.Add(COl1, COl2)
da.Update(ds, "sql_server_table")
I found that it was better to add to the table row by row if your table has a primary key. Inserting the entire table at once creates a conflict on the auto increment.
Here's my stored Proc
CREATE PROCEDURE dbo.usp_InsertRowsIntoTable
#Year int,
#TeamName nvarchar(50),
AS
INSERT INTO [dbo.TeamOverview]
(Year,TeamName)
VALUES (#Year, #TeamName);
RETURN
I put this code in a loop for every row that I need to add to my table:
insertRowbyRowIntoTable(Convert.ToInt16(ddlChooseYear.SelectedValue), name);
And here is my Data Access Layer code:
public void insertRowbyRowIntoTable(int ddlValue, string name)
{
SqlConnection cnTemp = null;
string spName = null;
SqlCommand sqlCmdInsert = null;
try
{
cnTemp = helper.GetConnection();
using (SqlConnection connection = cnTemp)
{
if (cnTemp.State != ConnectionState.Open)
cnTemp.Open();
using (sqlCmdInsert = new SqlCommand(spName, cnTemp))
{
spName = "dbo.usp_InsertRowsIntoOverview";
sqlCmdInsert = new SqlCommand(spName, cnTemp);
sqlCmdInsert.CommandType = CommandType.StoredProcedure;
sqlCmdInsert.Parameters.AddWithValue("#Year", ddlValue);
sqlCmdInsert.Parameters.AddWithValue("#TeamName", name);
sqlCmdInsert.ExecuteNonQuery();
}
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (sqlCmdInsert != null)
sqlCmdInsert.Dispose();
if (cnTemp.State == ConnectionState.Open)
cnTemp.Close();
}
}
From my understanding of the question,this can use a fairly straight forward solution.Anyway below is the method i propose ,this method takes in a data table and then using SQL statements to insert into a table in the database.Please mind that my solution is using MySQLConnection and MySqlCommand replace it with SqlConnection and SqlCommand.
public void InsertTableIntoDB_CreditLimitSimple(System.Data.DataTable tblFormat)
{
for (int i = 0; i < tblFormat.Rows.Count; i++)
{
String InsertQuery = string.Empty;
InsertQuery = "INSERT INTO customercredit " +
"(ACCOUNT_CODE,NAME,CURRENCY,CREDIT_LIMIT) " +
"VALUES ('" + tblFormat.Rows[i]["AccountCode"].ToString() + "','" + tblFormat.Rows[i]["Name"].ToString() + "','" + tblFormat.Rows[i]["Currency"].ToString() + "','" + tblFormat.Rows[i]["CreditLimit"].ToString() + "')";
using (MySqlConnection destinationConnection = new MySqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["ConnectionString"].ToString()))
using (var dbcm = new MySqlCommand(InsertQuery, destinationConnection))
{
destinationConnection.Open();
dbcm.ExecuteNonQuery();
}
}
}//CreditLimit