I'm new to SQL integration with C# WinForms stuff. I have an existing database and simply want to take the values from the text boxes on my form and efficiently write all of them to one row in a SQL Server database.
So this is what I've got, I was trying to make something generic, but if this isn't a good practice, let me know.
Every time I call this, it creates a new row. I know this is because of the ...Rows.Add() line but since my database table has a whole bunch of columns and the form has a bunch of textboxes, I was hoping to not make a gigantic command string.
static public void addToExistingTable(string table, string column, string value, SqlDbType valueType)
{
try
{
using (SqlConnection con = new SqlConnection(Global.connectionString))
{
using (SqlDataAdapter dataAdapter = new SqlDataAdapter())
{
string selectString = "SELECT " + column + " from dbo." + table;
string insertString = "INSERT into dbo." + table + " (" + column + ") values (#" + column + ")";
dataAdapter.SelectCommand = new SqlCommand(selectString, con);
dataAdapter.InsertCommand = new SqlCommand(insertString, con);
dataAdapter.InsertCommand.Parameters.Add(new SqlParameter(column, valueType, value.Length, column));
using (DataSet dataSet = new DataSet())
{
dataAdapter.Fill(dataSet);
DataRow newRow = dataSet.Tables[0].NewRow();
newRow[column] = value;
dataSet.Tables[0].Rows.Add(newRow);
dataAdapter.Update(dataSet);
}
}
}
}
catch (SqlException exp)
{
Console.WriteLine("Insert Error: " + exp.Message);
}
}
Please let me know if there is a good practice or resource to add a new row to a SQL database from a collection of form controls (textboxes).
Related
I have code that adds a value inside a SQL table :
SqlCommand command;
SqlDataAdapter adapter = new SqlDataAdapter();
String strSQL = "";
strSQL = "INSERT INTO tblTest (value1) VALUES ('" + strPLCData + "')";
command = new SqlCommand(strSQL, cnn);
adapter.InsertCommand = new SqlCommand(strSQL, cnn);
try
{
int rows = adapter.InsertCommand.ExecuteNonQuery();
txtStatusLogging.Text += "Inserted " + rows + " row(s) in the database." + Environment.NewLine;
}
catch (Exception ex)
{
MessageBox.Show("Failed to write to database : " + ex.Message);
}
command.Dispose();
But I'm a bit stuck when I want to add an unknown count of values in the database (according to a list of unknown size).
e.g. sometimes add only value1, other times add value1, value2 and value3 .... (depending on whats in a certain list).
How would I go about doing this?
There's absolutely no need for that SqlDataAdapter. If you want to add an arbitrary number of values to a table - use a straight INSERT SqlCommand and just loop over the list of values to insert.
Also: you should always use parametrized queries - no exceptions - and you should put your SqlConnection and SqlCommand objects in using () { ... } blocks - something like this:
Something like this:
public void InsertValues(List<int> values)
{
// define the insert query
string qryInsert = "INSERT INTO dbo.tblTest (value1) VALUES (#singleValue);";
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand cmdInsert = new SqlCommand(qryInsert, conn))
{
// define parameter
cmdInsert.Parameter.Add("#singleValue", SqlDbType.Int);
conn.Open();
// loop over values
foreach (int aValue in values)
{
// set the parameter value, execute query
cmdInsert.Parameters["#singleValue"].Value = aValue;
cmdInsert.ExecuteNonQuery();
}
conn.Close;
}
}
This is the function for automatically stored value to TotalAmt_tx.Text..
void TotalAmount()
{
.
.
.
.
TotalAmt_tx.Text = Total.ToString("00.00");
.
.
.
catch { }
}
Save button code :here the image of my forms
private void Save_bt_Click(object sender, EventArgs e)
{
//Purchase Table
{
string insertPur = "Insert into Purchase (Invoice,VendorName,PurchaseDate,TotalAmt) values ("+Invoice_tx.Text+"," +
"'"+VendorName_cb.Text+"','"+PurchaseDate_dt.Value.Date.ToString()+"',"+TotalAmt_tx.Text+" )";
OleDbDataAdapter da = new OleDbDataAdapter(insertPur, conn);
DataSet ds = new DataSet();
da.Fill(ds);
}
//Purchase Item Table
for (int i = 0; i < metroGrid1.Rows.Count; i++)
{
string insertPur = "Insert into PurchaseItem (Invoice, PId, Product, Qty, Rate, Amount) values (" + Invoice_tx.Text + "," +
""+metroGrid1.Rows[i].Cells["PId"].Value.ToString()+ ",'" + metroGrid1.Rows[i].Cells["Product"].Value.ToString() + "'," +
"" + metroGrid1.Rows[i].Cells["Qty"].Value.ToString() + "," + metroGrid1.Rows[i].Cells["Rate"].Value.ToString() + "," +
"" + metroGrid1.Rows[i].Cells["Amount"].Value.ToString() + ")";
OleDbDataAdapter da = new OleDbDataAdapter(insertPur, conn);
DataSet ds = new DataSet();
da.Fill(ds);
}
MessageBox.Show("Data Saved!!");
The problems show up because this
TotalAmt_tx.Text = Total.ToString("00.00")
What should I do, to solve it??
I've try follow some tutorial about formatting string but nothings works.
Please help
I suggest you try to use OleDbParameter Class, because if one of the values you combine to your query string has the , character it will mess-up you query (for example a number in the following format 1,000).
Hope it helps!
You should always stick to parameterized queries to avoid SQL Injection. It also helps in avoiding mistakes like missing a "'"
using (OleDbConnection connection =new OleDbConnection(connectionString))
{
var query = "Insert into Purchase (Invoice,VendorName,PurchaseDate,TotalAmt) values (#invoice,#vendor,#purchasedate,#amt)";
OleDbDataAdapter adapter = new OleDbDataAdapter(queryString, connection);
adapter.SelectCommand.Parameters.Add("#invoic", OleDbType.Integer).Value = Convert.ToInt32(Invoice_tx.Text);
adapter.SelectCommand.Parameters.Add("#vendor", OleDbType.VarChar,100).Value = VendorName_cb.Text;
adapter.SelectCommand.Parameters.Add("#invoic", OleDbType.Date).Value = PurchaseDate_dt.Value.Date; // I do not know what PurchaseDate_dt.Value.Date type is, so I leave it to you to convert to approapriate type
adapter.SelectCommand.Parameters.Add("#CategoryName", OleDbType.Integer).Value = Convert.ToInt32(TotalAmt_tx.Text);
connection.Open();
DataSet ds = new DataSet();
adapter.Fill(ds);
}
I am not getting, how to do insert and update of the data in C# WinForms on single button click.
private void save_Click(object sender, EventArgs e)
{
SqlConnection cn = new SqlConnection();
cn.ConnectionString = "data source=Sai;database=kaur; user id=sa;password=azxc;";
cn.Open();
string gen;
if (radioButton1.Checked == true)
gen = "Male";
else
gen = "Female";
string clas = null;
clas = comboBox1.Text;
string section = null;
section = comboBox2.Text;
SqlCommand cmd = new SqlCommand();
cmd.CommandText = "insert into studetail values('" + textBox1.Text + "','" + textBox2.Text + "','" + gen + "','" + textBox3.Text + "','" + clas + "','" + section + "')";
cmd.Connection = cn;
int n = cmd.ExecuteNonQuery();
if (n > 0)
MessageBox.Show(n + " Row Inserted.");
else
MessageBox.Show("Insertion failed.");
SqlDataAdapter da = new SqlDataAdapter("select * from studetail ", cn);
DataTable dt = new DataTable();
da.Fill(dt);
dataGridView1.DataSource = dt;
You can add a deletion before the insertion:
private void save_Click(object sender, EventArgs e)
{
DeletePerson(id); // add this
SqlConnection cn = new SqlConnection();
...
}
public void DeletePerson(int id)
{
using(SqlConnection connection = new SqlConnection(credentials))
{
connection.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = connection;
cmd.CommandText = "delete from studetail where someUniqeIdColumn = " + id;
cmd.ExecuteNonQuery();
}
}
Using responsible to dispose the connection.
Consider using Entity Framework or LINQ to SQL.
You are exposed to SQL injection.
First off the SQL query isn't quite right. It should look something like the following:
INSERT INTO studetail (columnName1, columnName2, ...columnNameN)
VALUES (value1, value2, ...valueN);
Where the column names are the columns where you want data to be inserted, and the values are the data you want inserted into said columns.
You should also be disposing the connection by wrapping the connection within a using statement.
using(var con = new SqlConnection(connectionString))
{
con.Open();
//rest of code that needs a connection here
}
Additionally, you need to be wary of SQL injection. I highly suggest reading this example from the MSDN website. It will give you an example of using an SQL Update and avoiding SQL injection with use of SqlCommand.Paramaters property.
You should also have a Primary Key in your database tables, if you don't already, so you can uniquely identify each record in a table.
To do an update and a save on the same button, you will need to check if a row already exists for the data that is being edited. This when a Primary comes in handy. You will want to check your database to see if a record already exists
SELECT 1 FROM studetail WHERE <Condition>
The WHERE condition will be the way you uniquely identify (a Primary Key) a row in your table. If the rows in the table are uniquely identified, the above SQL statement will return 1 if a value exists, which means you can UPDATE or 0 if no record exists, so you can INSERT
My SQL code inserts 10,000 records into a table from list. If record already exists, it updates a few fields.
Currently it taking more than 10 minutes and timing out unless I restrict the number of records to process. Is there anything in my code which I can do to solve this problem.
foreach(RMSResponse rmsObj in rmsList) {
try {
string connectionString = #"server=localhost\sqlexpress;" + "Trusted_Connection=yes;" + "database=MyDB; " + "connection timeout=30";
SqlConnection conn = new SqlConnection(connectionString);
conn.Open();
string str = "";
str += "SELECT * ";
str += "FROM RMSResponse ";
str += "WHERE LeadID = #RecruitID";
int LeadID;
Boolean IsPositive = true;
SqlCommand selectCommand = new SqlCommand(str, conn);
selectCommand.CommandType = CommandType.Text;
selectCommand.Parameters.Add(new SqlParameter("#RecruitID", rmsObj.RecruitID));
SqlDataReader sqlDataReader = selectCommand.ExecuteReader();
bool hasRows = sqlDataReader.HasRows;
while (sqlDataReader.Read()) {
LeadID = sqlDataReader.GetInt32(1);
IsPositive = sqlDataReader.GetBoolean(2);
IsPositive = (IsPositive == true) ? false : true;
Console.WriteLine("Lead ID: " + LeadID + " IsPositive: " + IsPositive);
}
sqlDataReader.Close();
if (hasRows) {
SqlCommand updateCommand = new SqlCommand("UPDATE RMSResponse set IsPositive=#IsPositive, OptOutDate=#OptOutDate where LeadID=#LeadID", conn);
updateCommand.Parameters.AddWithValue("#LeadID", rmsObj.RecruitID);
updateCommand.Parameters.AddWithValue("#IsPositive", IsPositive);
updateCommand.Parameters.AddWithValue("#OptOutDate", DateTime.Now);
updateCommand.ExecuteNonQuery();
sqlDataReader.Close();
}
if (!hasRows) {
SqlCommand insertCommand = new SqlCommand("INSERT INTO RMSResponse (LeadID, IsPositive, ReceivedDate) " + "VALUES(#LeadID, #IsPositive, #ReceivedDate)", conn);
insertCommand.Parameters.AddWithValue("#LeadID", rmsObj.RecruitID);
insertCommand.Parameters.AddWithValue("#IsPositive", true);
insertCommand.Parameters.AddWithValue("#ReceivedDate", DateTime.Now);
int rows = insertCommand.ExecuteNonQuery();
}
} catch (SqlException ex) {
Console.WriteLine(ex.Message);
}
}
You can move the update to SQL - all you are doing is setting the OptOutDate to be today. You can pass in the list of lead IDs to a batch update statement.
To insert records, you could bulk insert into a staging table, then execute SQL to insert the data for IDs that aren't already in the table.
There isn't much logic in your C#, so pulling the data out then putting it back in is making it unnecessarily slow.
If you don't want to go down this root, then other tips include:
Open one connection outside of the loop
Create one SqlCommand object outside of the loop and reuse it by resetting the paramenters
Change your select SQL to only select the columns you need, not *
A simple update or insert statement should never take 10 mins.
SqlServer is a very good database.
Create an index on LeadID on your table RMSResponse.
If your foreach is looping over many records, definitely consider a stored procedure, stored procedures will reduces a lot of the time taken.
If you want to Update or Insert(UPSERT) look at the Merge command added in SqlServer 2008.
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