Using ExecuteReader to return a primary key - c#

How Do I Find the ID from the first query and return this value so it can be inserted into query2? This is the code that needs done when a user completes a form on front end. I need to populate two tables and they will relate through the ID "StoryID" which is a primary key that is automatically created.
protected void Upload2_Click(object sender, EventArgs e)
{
userStoryForm.Visible = false;
info.Text = "You have successfully added a new user story.";
String connectionString = WebConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
String usernameData = username.Text.ToString();
int captureProjectID = Convert.ToInt32(Request.QueryString.Get("ProjectID"));
String storyno = StoryNoTextBox.Text;
String userstory = StoryTextTextBox.Text;
//Create connection
SqlConnection myConnection = new SqlConnection(connectionString);
//open connection
myConnection.Open();
String query = "INSERT INTO UserStories (StoryNo, StoryText, ProductOwner, ProjectID) " +
"VALUES ('" + storyno + "','" + userstory + "','" + usernameData + "','" + captureProjectID + "')" +
"SELECT SCOPE_IDENTITY() AS StoryID;";
SqlCommand myCommand = new SqlCommand(query, myConnection);
// Call GetOrdinal and assign value to variable.
SqlDataReader reader = myCommand.ExecuteReader();
int StoryIDData = reader.GetOrdinal("StoryID");
// Use variable with GetString inside of loop.
while (reader.Read())
{
Console.WriteLine("StoryID={0}", reader.GetString(StoryIDData));
}
// Call Close when done reading.
reader.Close();
//insert productowner, projectID and storyID into ProductBacklog table
String query2 = "INSERT INTO ProductBacklog (ProductOwner, ProjectID, StoryID) VALUES ('" + usernameData + "', #returnProjectID,'" + StoryIDData + "')";
SqlCommand myCommand2 = new SqlCommand(query2, myConnection);
myCommand2.Parameters.AddWithValue("#returnProjectID", captureProjectID);
//close connection
myConnection.Close();
}
}

Most important - use parameters in your SQL command. Never concatenate strings like that. You're asking for an SQL injection attack.
string query = #"
INSERT INTO UserStories (StoryNo, StoryText, ProductOwner, ProjectID)
VALUES (#storyno, #userstory, #usernameData, #captureProjectID)
SELECT CAST(SCOPE_IDENTITY() AS INT)";
SqlCommand myCommand = new SqlCommand(query);
myCommand.Parameters.Add("#storyno", DbType.String).Value = storyno;
...
To get the returned id, use ExecuteScalar():
int StoryIDData = (int)myCommand.ExecuteScalar();
Also, you don't dispose your resources correctly. If an exception is thrown in the method, the SQLConnection will not be closed. You should put it in a using statement.

Related

C# Updating excel database and inserting record while adding items

so I have this program which when I press a button inserts a record into an excel spreadsheet with, the columns, being , customer, product, weight, dateTime. Now I want to be able to update a record if the same customer, and product occurs, but I also want to add the previous weight field with the new field, and update the time.
The problem is i'm not sure how to modify my update statement to do this.
// Load data from database, and Update database if filed already exists
DataSet ds = new DataSet();
string insertquery = "SELECT * FROM [Sheet1$] where [Customer] = '" + lblcustomername + " ' ";
OleDbConnection myConnection = new OleDbConnection(OutputDatabaseConnectionString); //define new connection object
OleDbDataAdapter mydataadapter = new OleDbDataAdapter(insertquery, myConnection); //define data adaptor and select column data from spreadsheet
mydataadapter.Fill(ds);
int i = ds.Tables[0].Rows.Count;
// If item exists in database, update it
if (i > 0)
{
try
{
System.Data.OleDb.OleDbConnection myConnection2; //create new connection object
System.Data.OleDb.OleDbCommand myCommand = new System.Data.OleDb.OleDbCommand();
String sql = null;
myConnection2 = new System.Data.OleDb.OleDbConnection(OutputDatabaseConnectionString); //define connection string
myConnection2.Open();
myCommand.Connection = myConnection2;
sql = "UPDATE [Sheet1$] SET [Net Weight(Kg)]= '" + textBox1.Text + "' WHERE [Customer] = '" + lblcustomername + "'";
myCommand.CommandText = sql;
myCommand.ExecuteNonQuery();
myConnection2.Close();
myConnection2.Close(); //close connection
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
// if it doesn't exist update database
try
{
System.Data.OleDb.OleDbConnection myConnection1; //create new connection object
System.Data.OleDb.OleDbCommand myCommand = new System.Data.OleDb.OleDbCommand();
String sql = null;
myConnection1 = new System.Data.OleDb.OleDbConnection(OutputDatabaseConnectionString); //define connection string
myConnection1.Open();
myCommand.Connection = myConnection1;
sql = sql = "INSERT INTO [Sheet1$] ([Customer],[Product],[Net Weight(Kg)], [DateTime]) VALUES('" + lblcustomername.Text + "','" + lblproductname.Text + "','" + textBox1.Text + "','" + (DateTime.Now).ToString() + "')";
myCommand.CommandText = sql;
myCommand.ExecuteNonQuery();
myConnection1.Close();
myConnection1.Close(); //close connection
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}

C# Exception thrown: 'System.Data.SqlClient.SqlException' in System.Data.dll

Apologies in advance if I missed an answer to this somewhere but I wasn't quite finding it anywhere. So I'm building an application that scans PDF's of service orders our company gets, parses it, and inserts it into a SQL DB. The problem is at the end of this code. It successfully :
saves the original pdf in the proper folder
scans the pdf and parses it
inserts the correct data into the service order table
grabs PK of service order just created as we need that for the next batch of inserts
Here is where it gets hung up with a Exception thrown: 'System.Data.SqlClient.SqlException' in System.Data.dll
I foreach through all the instruments as there are multiples per Service Order, but it is erroring on this somewhere. to be clear I put a break point on the insert statement and all of the data is good and in the proper format ("string" int)
I feel like its in my connection maybe?
Anyways, thanks in advance for the help.
string filename = Path.GetFileName(FileUpload1.FileName);
FileUpload1.SaveAs(Server.MapPath("~/PDF/") + filename);
// Now we parse the PDF by creating a new ServiceOrder object and parsing from it.
ServiceOrder so = new ServiceOrder();
// Make sure we load the PDF from the correct path on the server
so.LoadPDF(Server.MapPath("~/PDF/") + filename);
String strConnString = "Data Source=127.0.0.0;Initial Catalog=SOMECATALOG;User ID=SOMEUSER;Password=SOMEPASSWORD";
// Insert Into Service Orders Table
string defaultdate = DateTime.Now.ToString("yyyy-MM-dd");
String strQuery = "insert into TServiceOrders (strServiceOrderNo, intStatusCodeID, strCustomerName, strCustomerNo, strCustomerAddress1, strCustomerAddress2, strCustomerAddress3, intRepID, strServiceDescription, strServiceRequestDate, strServiceOrderDate, strNotes) values ('"
+ so.ServiceOrderNumber.ToString() + "', 2, '"
+ so.CustomerContactName.ToString() + "', '"
+ so.CustomerNumber.ToString() + "', '"
+ so.CustomerContactAddress1.ToString() + "', '"
+ so.CustomerContactAddress2.ToString() + "', '"
+ so.CustomerContactAddress3.ToString() + "', 1, '', '"
+ defaultdate + "', '" + defaultdate + "', '')";
SqlConnection conn = new SqlConnection(strConnString);
SqlCommand cmd = new SqlCommand(strQuery, conn);
conn.Open();
cmd.ExecuteNonQuery();
conn.Close();
// Grabbing latest primary key od service order just added for next instrument inserts
int lastid = 999999;
String strPKquery = "select top 1 intServiceOrderID from TServiceOrders order by intServiceOrderID desc";
SqlDataReader rdr = null;
SqlConnection conn2 = new SqlConnection(strConnString);
SqlCommand cmd2 = new SqlCommand(strPKquery, conn2);
try
{
conn2.Open();
rdr = cmd2.ExecuteReader();
while (rdr.Read())
{
lastid = (int)rdr["intServiceOrderID"];
}
}
finally
{
if (rdr != null)
{
rdr.Close();
}
if (conn2 != null)
{
conn2.Close();
}
}
// Insert Into Service Instruments Tables
SqlConnection conn3 = new SqlConnection(strConnString);
conn3.Open();
foreach (ServiceInstrument sin in so.ServiceInstruments)
{
string sim = "";
sim = sin.ServiceInstrumentModel;
if (String.IsNullOrEmpty(sim))
{
sim = "";
}
else
{
sim = sin.ServiceInstrumentModel.ToString();
}
string sid = "";
sid = sin.ServiceInstrumentDescription;
if (String.IsNullOrEmpty(sid))
{
sid = "";
}
else
{
sid = sin.ServiceInstrumentDescription.ToString();
}
string sis = "";
sis = sin.ServiceInstrumentSerial;
if (String.IsNullOrEmpty(sis))
{
sis = "";
}
else
{
sis = sin.ServiceInstrumentSerial.ToString();
}
string sih = "";
sih = sin.ServiceInstrumentHandle;
if (String.IsNullOrEmpty(sih))
{
sih = "";
}
else
{
sih = sin.ServiceInstrumentHandle.ToString();
}
string sip = "";
sip = sin.ServiceInstrumentParentAsset;
if (String.IsNullOrEmpty(sip))
{
sip = "";
}
else
{
sip = sin.ServiceInstrumentParentAsset.ToString();
}
String strQuery3 = "insert into TServiceInstruments values ('" + sim.ToString() + "', '" + sid.ToString() + "', '" + sis.ToString() + "', '" + sih.ToString() + "', " + sip.ToString() + ", " + lastid + ")";
SqlCommand cmd3 = new SqlCommand(strQuery3, conn3);
cmd3.ExecuteNonQuery();
}
conn3.Close();
When writing insert statements you should always specify the column names. This will protect the code from changes in the order of the columns in the table schema.
You are not using parameters in your sql statements, this leaves your code vulnerable to Sql Injection.
You should use using statements around your SqlConnection instances to ensure they are closed even when an Exception occurs.
Your logic is very difficult to follow, split your code until methods with meaningful names instead of having 1 "God" method that does everything.
If you follow those guidelines the problem will most likely solve itself in your refactoring.
Update Code Fragment
Note that you should always specify the correct types for your columns and the length if applicable. Also pass the actual value and never the string value.
const String strQuery3 = "INSERT INTO TServiceInstruments (sim, sid, sis, sih, sip, lid) VALUES (#sim, #sid, #sis, #sih, #sip, #lid)";
using(var conection = new SqlConnection(strConnString))
using(SqlCommand command = new SqlCommand(strQuery3, connection))
{
command.Parameters.Add(new SqlParameter("#sim", SqlDbType.VarChar, 200){Value = sim});
command.Parameters.Add(new SqlParameter("#sid", SqlDbType.VarChar, 200){Value = sid});
command.Parameters.Add(new SqlParameter("#sis", SqlDbType.VarChar, 200){Value = sis});
command.Parameters.Add(new SqlParameter("#sih", SqlDbType.VarChar, 200){Value = sih});
command.Parameters.Add(new SqlParameter("#sip", SqlDbType.Int){Value = sip});
command.Parameters.Add(new SqlParameter("#lid", SqlDbType.Int){Value = lid});
connection.Open();
command.ExecuteNonQuery();
}
Final note: You really need to learn how to read Exceptions and this includes the Stack Trace which points directly to the line in the call stack where the Exception originated. If you can understand this then debugging becomes much easier.
Maybe this doesn't deserve to be an answer, but I'm trying to build some reputation, so here goes :).
I suspect that your error lies in the "insert into TServiceInstruments ..." statement. Namely, you are giving the table more (or less) columns. As a good practice, always specify the columns, like this:
insert into TServiceInstruments (column1, column2, column3)
values (1, 2, 3)

How to create connection between MySQL table to query in C#

I wrote the query for inserting data to MySQL table "Persons":
SqlConnection con = new SqlConnection();
try
{
String insert = "INSERT INTO Persons (id,Name,Surname,Address,Phone) VALUES ('" + txtId.Text + "','" + txtName.Text + "','" + txtSurname.Text + "','" + txtAddress.Text + "','" + txtPhone.Text + "')";
con.Open();
SqlCommand cmd = new SqlCommand(insert,con);
cmd.ExecuteNonQuery();
con.Close();
}
catch
{
MessageBox.Show("Id is not valid");
}
But it's not working. I have one connection for the whole database, but it's not working for a specific table. How I can create a connection between specific table to query in C#?
What is it? SqlConnection con = new SqlConnection() you need to pass a connection string which comprises DBname, username, pasword, server name ... etc; you are not passing those information anywhere then how can you expect it to connect to your database without having the information.
Pass the connection string either in constructor or using the property.
SqlConnection con = new SqlConnection(connection_string)
(OR)
SqlConnection con = new SqlConnection();
con.ConnectionString = connection_string;
There are different ways to insert data into the tables. I suggest to use parametrized sql query to keep safe from malicious occurrence.
Firstly you should have a ConnectionString something like this:
string connectionString = "Persist Security Info=False;User ID=UserName;Password=YourPassword;Server=ServerName";
And than:
using (SqlConnection connection = new SqlConnection(connectionString))
{
SqlCommand cmd = new SqlCommand("INSERT INTO TableName (Col1, Col2, ColN) VALUES (#Col1, #Col2, #ColN)");
cmd.CommandType = CommandType.Text;
cmd.Connection = connection;
cmd.Parameters.AddWithValue("#Col1", txtName.Text);
cmd.Parameters.AddWithValue("#Col2", txtPhone.Text);
cmd.Parameters.AddWithValue("#ColN", txtAddress.Text);
connection.Open();
cmd.ExecuteNonQuery();
}
Try this code. Please edit your credentials before trying.
Replace localhost with SQL server instance name, user id with your MySQL server instance user id, password with your MySQL server instance password and testdb with your database name. It should work fine.
string connectionString = #"server=localhost;user id=admin;password=admin;database=testdb;";
SqlConnection con = new SqlConnection(connectionString);
try
{
String insert = "INSERT INTO Persons (id,Name,Surname,Address,Phone) VALUES ('" + txtId.Text + "','" + txtName.Text + "','" + txtSurname.Text + "','" + txtAddress.Text + "','" + txtPhone.Text + "')";
con.Open();
SqlCommand cmd = new SqlCommand(insert,con);
cmd.ExecuteNonQuery();
con.Close();
}
catch
{
MessageBox.Show("Id is not valid");
}

Insert data to Mysql getting slower and slower

I need to insert 388 datas per minute to local Database.
At first when the table is Empty, I only need 5 second to Insert to database.
But when the table gets larger, the program efficacy slow down to more than one minute when the amount of rows comes to 1,026,558.
And the useage of CPU is 100%. It's unusual.
here is my code:
public static void dataToDB(String[] routeIDArray,String[] levelArray,String[] valueArray,String[] travelTimeArray, int amountOfData)
{
MySqlConnection con = new MySqlConnection(connStr);
MySqlCommand cmd = null;
MySqlDataReader rdr = null;
String sqlCmd, updateSqlCmd = "UPDATE `datetimetable` SET ";
for(int counter = 0; counter < amountOfData; counter++)
{
sqlCmd = "ALTER TABLE `datetimetable` ADD COLUMN IF NOT EXISTS `" + routeIDArray[counter] + "` INT NULL;"
+ "INSERT INTO `roadvalue`.`data` (`level`,`value`,`traveltime`) VALUES ("
+ levelArray[counter] + ","
+ valueArray[counter] + ","
+ travelTimeArray[counter] + ");"
+ "SELECT LAST_INSERT_ID() FROM `data`;";
cmd = new MySqlCommand(sqlCmd, con);
con.Open();
rdr = cmd.ExecuteReader();
rdr.Read();
updateSqlCmd += "`" + routeIDArray[counter] + "` = " + rdr[0] + ",";
rdr.Close();
}
updateSqlCmd = updateSqlCmd.TrimEnd(',');
updateSqlCmd += " WHERE EXISTS (SELECT * WHERE dateTime = '" + dateTime.ToString("yyyy-MM-dd HH:mm:00") + "');";
cmd = new MySqlCommand(updateSqlCmd, con);//update data key to datetimetable
cmd.ExecuteNonQuery();
Console.WriteLine("Done.");
con.Close();
}
public static void checkDateTimeExisted()
{
MySqlConnection con = new MySqlConnection(connStr);
MySqlCommand cmd;
String sqlCmd;
sqlCmd = "INSERT INTO `datetimetable` (`dateTime`) SELECT * FROM (SELECT '" + dateTime.ToString("yyyy-MM-dd HH:mm:00")
+ "') AS tmp WHERE NOT EXISTS(SELECT `dateTime` FROM `datetimetable` WHERE `dateTime` = '" + dateTime.ToString("yyyy-MM-dd HH:mm:00") + "') LIMIT 1; ";
con.Open();
cmd = new MySqlCommand(sqlCmd, con);
cmd.ExecuteNonQuery();
con.Close();
}
And Mysql Engine is InooDB, table "data" has one Auto_Increment Primary key, table "datetimetable" has an Auto_Increment Primary key and a not duplicate datetime as index.
What have I done wrong?
I find the answer, the command "SELECT LAST_INSERT_ID() FROM data;" should add LIMIT 1 or it will get all the ID kill the performance.
Do not use ALTER TABLE in a loop -- Plan ahead and provide all the columns before starting.
Do not use multiple statements in a single string. This has security implications, etc.
Do not use WHERE EXISTS... when (I think) a simple WHERE would work.
If there is UNIQUE(datetime), then the final INSERT can be simply
INSERT IGNORE INTO datetimetable
(datetime)
VALUE
('...');
Do batch inserts unless you need the LAST_INSERT_ID(). LIMIT 1 should not be necessary.
Do not 'Normalize' datetime values; it only slows things down. Just put the datetime as is in the main table.

Trying to use code to insert a row into the database and then also display that row after a button is clicked (using CommandText)

I'm trying to use code to insert a row into the database and then immediately display that code after after a button is clicked. I'm using C#.
comm.CommandText = "INSERT INTO Store (FirstName, LastName) Values ('" + txtFirstName.Text + "', '" + txtLastName.Text + "')";
The above code works . But it won't work if I add the following code (which will work instead):
comm.CommandText = "Select FirstName, LastName from Store";
When the button is clicked, I want to insert the row (containing information that was just entered from the textbox) into the table and also display that new row into a form (set up to view the table). I'm trying to get both of the commands to work at the same time, but only the second "Command" works.
Here is what the surrounding code looks like:
protected void btnSubmit_Click(object sender, EventArgs e)
{
String testVar = txtFirstName.Text;
OleDbConnection conn = new OleDbConnection(); //where to find db
conn.ConnectionString = ConfigurationManager.ConnectionStrings["storeConnString"].ConnectionString; //long connection screen.
conn.Open();
OleDbCommand comm = conn.CreateCommand();
comm.Connection = conn;
comm.CommandText = "INSERT INTO Store (FirstName, LastName) Values ('" + txtFirstName.Text + "', '" + txtLastName.Text + "')";
comm.CommandText = "Select FirstName, LastName from Store";
OleDbDataReader reader = comm.ExecuteReader();
(I know I need to use parameters, but I'm going to do that after I figure this out.)
Thanks, Brad
Because after this two lines, your INSERT command will not assigned to your comm anymore.
comm.CommandText = "INSERT INTO Store (FirstName, LastName) Values ('" + txtFirstName.Text + "', '" + txtLastName.Text + "')";
comm.CommandText = "Select FirstName, LastName from Store";
CommandText property only have now your SELECT stament. Just execute your INSERT query with ExecuteNonQuery and after use ExecuteReader to get your SELECT statement result.
comm.CommandText = "INSERT INTO Store (FirstName, LastName) Values ('" + txtFirstName.Text + "', '" + txtLastName.Text + "')";
comm.ExecuteNonQuery();
comm.CommandText = "Select FirstName, LastName from Store";
OleDbDataReader reader = comm.ExecuteReader();
As you said, you should always use parameterized queries. This kind of string concatenations are open for SQL Injection attacks.
And use using statement to dispose your OleDbConnection, OleDbCommand and OleDbDataReader like;
using(OleDbConnection conn = new OleDbConnection(conString))
using(OleDbCommand comm = conn.CreateCommand())
{
// Execute your INSERT query here.
// Also check your INSERT is successfull or not.
// Assing your SELECT statement to your CommandText property
using(OleDbDataReader reader = comm.ExecuteReader())
{
//
}
}

Categories

Resources