C# Access insert query not working - c#

Okay so this code produces no errors but doesn't add the data to the database. When a button is pressed, it should insert all values in the text boxes into the database.
private void addSportButton_Click(object sender, EventArgs e){
for(int i = 0; i < numberOfPlayers; i++){
OleDbConnection connection = new OleDbConnection(CONNECTION STRING HERE);
OleDbCommand command = new OleDbCommand();
command.CommandText = "INSERT INTO TotalPlayerName ([PlayerName]) VALUES (#name)";
command.CommandType = CommandType.Text;
command.Connection = connection;
connection.Open();
command.Parameters.Add("#name", OleDbType.VarWChar).Value = textBox[i].Text;
command.ExecuteNonQuery();
connection.Close();
}
}
What am I doing wrong?
EDIT:
changed some things around in previous sections of code and now there are rows added but nothing appears in the PlayerName field
Code for creating the text boxes
for (int t = 0; t < 18; t++)
{
textBox[t] = new TextBox();
this.Controls.Add(textBox[t]);
this.textBox[t].Font = new System.Drawing.Font("Calibri", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
// if it is the first text box then it must go in this location
if (t == 0)
{
textBox[t].Location = new Point(32, 41);
textBox[t].Visible = true;
}
else
{
// every other text box will be 27px below the previous
textBox[t].Location = new System.Drawing.Point(32, 41 + (t * 27));
textBox[t].Visible = false;
}
}

Nine times out of ten, when an insert 'fails' and there is no error message....you are looking in the wrong database.
You are inserting to database 'A'
But looking for the record in database 'B'

Related

This C# / sql query code takes a lot of time to update the table

Can anyone help improve performance? Updating the table takes a lot of time.
I am updating the serial number from datagridview to a table called dbo.json
// UPDATE dbo.json with numbers
private void BtnUpdateSql_Click(object sender, EventArgs e)
{
string VAL1;
string VAL2;
foreach (DataGridViewRow row in DgvWhistlSorted.Rows)
if (string.IsNullOrEmpty(row.Cells[5].Value as string))
{
}
else
{
for (int i = 0; i <= DgvWhistlSorted.Rows.Count - 2; i++)
{
VAL1 = DgvWhistlSorted.Rows[i].Cells[6].Value.ToString();
VAL2 = DgvWhistlSorted.Rows[i].Cells[0].Value.ToString();
var cnn = ConfigurationManager.ConnectionStrings["sql"].ConnectionString;
using (var con = new SqlConnection(cnn))
{
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.Text;
cmd.CommandText = "UPDATE dbo.json SET RowN = #VAL1 WHERE [A-order] = #VAL2";
cmd.Parameters.AddWithValue("#VAL1", VAL1);
cmd.Parameters.AddWithValue("#VAL2", VAL2);
cmd.Connection = con;
con.Open();
cmd.ExecuteNonQuery();
con.Close();
}
}
}
MessageBox.Show("dbo.json is ready");
}
You shouldn't create the connection and command inside such a tight loop - create and open the connection and command ONCE before the loop, and in the loop, only set the parameter values and execute the query for each entry.
Something like this:
// UPDATE dbo.json with numbers
private void BtnUpdateSql_Click(object sender, EventArgs e)
{
string VAL1;
string VAL2;
// define connection string, query text *ONCE* before the loop
string cnn = ConfigurationManager.ConnectionStrings["sql"].ConnectionString;
string updateQuery = "UPDATE dbo.json SET RowN = #VAL1 WHERE [A-order] = #VAL2;";
// create connection and command *ONCE*
using (SqlConnection con = new SqlConnection(cnn))
using (SqlCommand cmd = new SqlCommand(updateQuery, cnn))
{
// Define parameters - adapt as needed (don't know the actual datatype they have)
cmd.Parameters.Add("#VAL1", SqlDbType.VarChar, 100);
cmd.Parameters.Add("#VAL2", SqlDbType.VarChar, 100);
// open connection ONCE, for all updates
con.Open();
foreach (DataGridViewRow row in DgvWhistlSorted.Rows)
{
if (!string.IsNullOrEmpty(row.Cells[5].Value as string))
{
for (int i = 0; i <= DgvWhistlSorted.Rows.Count - 2; i++)
{
VAL1 = DgvWhistlSorted.Rows[i].Cells[6].Value.ToString();
VAL2 = DgvWhistlSorted.Rows[i].Cells[0].Value.ToString();
// set the values
cmd.Parameters["#VAL1"].Value = VAL1;
cmd.Parameters["#VAL2"].Value = VAL2;
// execute query
cmd.ExecuteNonQuery();
}
}
}
// close connection after all updates are done
con.Close();
}
MessageBox.Show("dbo.json is ready");
}
Create the connection ONCE...you're creating a new database connection each time through the loop! And in fact you do not need to create new command objects each time. You can reuse the command object because the parameters are the same. Just clear the params each time through the loop.
Also don't do the grid view count in the loop, set a variable for it.
string query = "UPDATE dbo.json SET RowN = #VAL1 WHERE [A-order] = #VAL2";
int counter = DgvWhistlSorted.Rows.Count - 2;
using (SqlConnection con = new SqlConnection(cnn))
{
con.Open();
using(SqlCommand cmd = new SqlCommand(cnn,query))
{
cmd.Parameters.Clear();
//Do your loop in here
for (int i = 0; i <= counter; i++)
{
VAL1 = DgvWhistlSorted.Rows[i].Cells[6].Value.ToString();
VAL2 = DgvWhistlSorted.Rows[i].Cells[0].Value.ToString();
cmd.Parameters.AddWithValue("#VAL1", VAL1);
cmd.Parameters.AddWithValue("#VAL2", VAL2);
cmd.ExecuteNonQuery();
}
}
}
A better idea is to do this in one command, by passing all the data in a Table-Value Parameter (TVP):
First create the table type. I don't know your data types, so I'm guessing here. Make sure to match the types to the existing table.
CREATE TYPE dbo.OrderJson (
Order int PRIMARY KEY,
RowN nvarchar(max) NOT NULL
);
Then you can pass the whole thing in one batch. You need to create a DataTable to pass as the parameter, or you can use an existing datatable.
// UPDATE dbo.json with numbers
private void BtnUpdateSql_Click(object sender, EventArgs e)
{
var table = new DataTable {
Columns = {
{ "Order", typeof(int) },
{ "RowN", typeof(string) },
},
};
foreach (DataGridViewRow row in DgvWhistlSorted.Rows)
if (!string.IsNullOrEmpty(row.Cells[5].Value as string))
table.Rows.Add(DgvWhistlSorted.Rows[i].Cells[0].Value, DgvWhistlSorted.Rows[i].Cells[6].Value)
const string query = #"
UPDATE dbo.json
SET RowN = t.RowN
FROM dbo.json j
JOIN #tmp t ON t.order = j.[A-order];
";
using (var con = new SqlConnection(ConfigurationManager.ConnectionStrings["sql"].ConnectionString))
using (var cmd = new SqlCommand(query, con))
{
cmd.Parameters.Add(new SqlParameter("#tmp", SqlDbType.Structured) { Value = table, TypeName = "dbo.OrderJson" });
con.Open();
cmd.ExecuteNonQuery();
}
MessageBox.Show("dbo.json is ready");
}
I found that the fastest way would be to save the DATAGRIDVIEW to an SQL table and continue the process with - stored procedure + update query - between two tables - now it flies ...
Thank you all

TableLayoutPanel does not display last 10 row of data

I need to create a table which will always display the last ten records of CTLog on a TableLayoutPanel. So whenever the user adds a new CTLog in Access database by clicking on a button, the table will dynamically update and display the last ten CTLogs. When adding the first ten records, I managed to get them on table but those records added after the 10th row cannot be displayed. I used the method of replacing the old labels on TableLayoutPanel by erasing the old one and then add the new ones.
private void RecentCT()
{
int j = 0;
for (j = 0; j < 10; j++)
{
tableLayoutPanel1.Controls.Remove(tableLayoutPanel1.GetControlFromPosition(j + 1, 0));
tableLayoutPanel1.Controls.Remove(tableLayoutPanel1.GetControlFromPosition(j + 1, 1));
}
string sql = "select Top 10 * from timer where ModelLog = #m and ShiftLog = #sl and ShiftStart = #ss and ShiftEnd = #se";
using (OleDbCommand cmd = new OleDbCommand(sql, connection))
{
//all cmd.Parameters.Add actions at here
try
{
connection.Open();
//List<string> results = new List<string>(); I used list and foreach previously
Label[] labels = new Label[10];
Label[] labels2 = new Label[10];
int i = 0;
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
labels[i] = new Label
{
Text = reader["CTLog"].ToString(),
Anchor = AnchorStyles.None,
Font = new Font("Microsoft Sans Serif", 10, FontStyle.Regular),
TextAlign = ContentAlignment.MiddleCenter
};
labels2[i] = new Label
{
Text = "Unit " + reader["UnitID"].ToString(),
Anchor = AnchorStyles.None,
Font = new Font("Microsoft Sans Serif", 10, FontStyle.Regular),
TextAlign = ContentAlignment.MiddleCenter
};
tableLayoutPanel1.Controls.Add(labels2[i], i + 1, 0);
tableLayoutPanel1.Controls.Add(labels[i], i + 1, 1);
i++;
}
}
connection.Close();
}
catch (Exception ex)
{
MessageBox.Show("Recent cycle time records cannot be retrieved. Error: " + ex.Message);
connection.Close();
}
}
}
Did I miss out something or something is wrong in my method?
Problem is with the sql query I used.
This is the correct sql query:
string sql = "select top 10 * from timer where ModelLog = #m and ShiftLog = #sl and ShiftStart = #ss and ShiftEnd = #se ORDER BY ID DESC";
To get the latest 10 rows of records, I must combine top and order by in desc form in a query. Because using only top keyword will only get the first 10 row, not the last ten rows.

Can't get the total row count

I have a table which has 3 columns and each column has 5 rows.Now I wanna get those total numbers of rows in c# to create that number of labels dynamically as well as get the rows value for labels name.Similarly, creates same numbers of the textbox as well.Then in the runtime, i wanted to submit the value to the database by this textbox.
Note: here, if I increase the rows of the table,then the label and textbox will be increased automatically/dynamically as well as submitting value through textbox will perfectly work.
But , all I have done is only getting count value 1 , I just tried a lot but not getting the total count value which is actually 5 .
here, is my code...
private void Form1_Load(object sender, EventArgs e)
{
string cs = ConfigurationManager.ConnectionStrings["DBCS"].ConnectionString;
using (SqlConnection con = new SqlConnection(cs))
{
//string cmText = "select ProductId,ProductName,UnitPrice from tblProductInventory";
string cmText = "Select Count(ProductId) from tblProductInventory";
SqlCommand cmd = new SqlCommand(cmText, con);
con.Open();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
int count = rdr.FieldCount;
while (rdr.Read())
{
//System.Windows.Forms.Label MyLabel;
{
int y = 50;
Label myLabel = new Label();
for (int i = 0; i < count; i++)
{
myLabel = new Label();
myLabel.Location = new Point(88, y);
myLabel.Name = "txtVWReadings" + i.ToString();
myLabel.Size = new Size(173, 20);
myLabel.TabIndex = i;
myLabel.Visible = true;
myLabel.Text = rdr[i].ToString();
y += 25;
this.Controls.Add(myLabel);
}
}
}
}
}
}
And I got this output.
The issue seems that you are using query as count but you want the values of the field. So you can probably change it to
string cs = ConfigurationManager.ConnectionStrings["DBCS"].ConnectionString;
using (SqlConnection con = new SqlConnection(cs))
{
//string cmText = "select ProductId,ProductName,UnitPrice from tblProductInventory";
string cmText = "Select Count(ProductId) from tblProductInventory";
SqlCommand cmd = new SqlCommand(cmText, con);
con.Open();
Int32 count = (Int32) cmd.ExecuteScalar();
int i = 1;
cmText = "select ProductId,ProductName,UnitPrice from tblProductInventory";
SqlCommand cmd1 = new SqlCommand(cmText, con);
using (SqlDataReader rdr = cmd1.ExecuteReader())
{
int y = 50;
Label myLabel = new Label();
TextBox MyTxt = New TextBox();
while (rdr.Read())
{
myLabel = new Label();
myLabel.Location = new Point(88, y);
myLabel.Name = "txtVWReadings" + i.ToString();
myLabel.Size = new Size(173, 20);
myLabel.TabIndex = i;
myLabel.Visible = true;
myLabel.Text = rdr[1].ToString(); //Since you want ProductName here
y += 25;
this.Controls.Add(myLabel);
//Same Way Just include the TextBox
//After all Position of TextBox
MyTxt.Text = rdr[2].ToString(); // I believe you need UnitPrice of the ProductName
i++;
}
}
}
Count(columname) :
Will count only the NOT NULL values in that column.
Count(*) :
Will count the number of records in that table.
So I guess you have some NULL values in ProductId column. Change it to
Select Count(*) from tblProductInventory

How to loop through textBox(i) in c#?

I've a situation here . I haven't written the code , as I don't have the idea even to kick it off!. I've 10 textboxes and a button , so when I finish typing into only 3 I'll use only three as the values I'm parsing into these textboxes go into the database.I'm planning to write a query in a for loop and execute it, so that only the text boxes which have value get into the database.
for(int i=0;i<9;i++)
{
string sql = "Insert Into exprmnt(docid,itemid,doctitle,itemcontent)values("+int.Parse(label6.Text)+","+i+",'"+label5.Text+"','"+textBox[i].Text+"')";
}
OleDbCommand cmd = new OleDbCommand(sql,con);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
this is something that I'd want to happen , it's okay if I've empty 'itemcontent' against some itemid 'i'which happens when I save all the text boxes including the ones that don't have any text keyed in.
To loop through textBox you can create an array of textBoxes you want to loop through:
TextBox[] tbs = {textBox1, textBox2, textBox3}; //put all into this array
for(int i = 0; i<tbs.Length; i++)
{
//use each textBox in here:
string text = tbs[0].Text; //this is an example of how to get the Text property of each textBox from array
}
For what it's worth, you can use Linq to find the filled textboxes. You're open for SQL-Injection. Use parameters instead of string concatenation:
int docid = int.Parse(label6.Text);
String doctitle = label5.Text;
var filledTextBoxes = this.Controls
.OfType<TextBox>()
.Select((txt,i) => new { Textbox = txt, Index = i })
.Where(x => x.Textbox.Text.Length != 0);
if(filledTextBoxes.Any())
{
using (OleDbConnection connection = new OleDbConnection(connectionString))
{
const String sql = "Insert Into exprmnt(docid,itemid,doctitle,itemcontent)values(#docid, #itemid, #doctitle, #itemcontent)";
connection.Open();
foreach(var txt in filledTextBoxes)
{
OledDbCommand cmd = new OledDbCommand(sql, connection);
// Set the parameters.
cmd.Parameters.Add(
"#docid", OleDbType.Integer).Value = docid;
cmd.Parameters.Add(
"#doctitle", OleDbType.VarChar, 50).Value = doctitle;
cmd.Parameters.Add(
"#itemid", OleDbType.Integer).Value = txt.Index;
cmd.Parameters.Add(
"#itemcontent", OleDbType.VarChar, 100).Value = txt.Textbox.Text;
try
{
int affectedRecords = cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
} // The connection is automatically closed when the code exits the using block.
}
Note that i've used the using-statement to ensure that the connection gets disposed(closed).
It worked finally!!!
#yogi thanks!
the code that worked is
List<TextBox> textBoxList = new List<TextBox>();
textBoxList.Add(new TextBox { Text = textBox1.Text });
textBoxList.Add(new TextBox { Text = textBox2.Text });
textBoxList.Add(new TextBox { Text = textBox3.Text });
textBoxList.Add(new TextBox { Text = textBox4.Text });
for (int n = 1; n<4; n++)
{
string sql = "Insert Into exprmnt (docid,itemid,doctitle,itemcontent) values(" + int.Parse(label6.Text) + "," + n + ",'" + label5.Text + "','" + textBoxList[n].Text+ "')";
OleDbCommand cmd = new OleDbCommand(sql, connection);
connection.Open();
cmd.ExecuteNonQuery();
connection.Close();
}
}
Add your textbox controls to a list.. then loop over the list.
List<TextBox> textBoxList = new List<TextBox>();
for (int i = 0; i < textBoxList.Count; i++) {
// .. do your thing here, using textBoxList[i].Text for the value in the textbox
}
Also, as Tim Schmelter pointed out.. you're open for SQL injection when concatenating your queries like that.

In C#, how do I handle Oracle Float types? Receiving error "Arithmetic operation resulted in an overflow"

I am using a generic approach to receiving a single row from any Oracle table and displaying it in a datagridview, using the code below. But, if the table contains a column of float type and the value has a large number of decimal places, I get "Arithmetic operation resulted in an overflow" at the line: MyReader.GetValues(objCells);
oCmd.CommandText = "OTCMIADM.OTCMI_GUI.GET_ROW";
oCmd.CommandType = CommandType.StoredProcedure;
oCmd.Parameters.Add("PI_TABLE_NAME", OracleDbType.Varchar2, 40).Value = cmbStagingTables.SelectedItem;
oCmd.Parameters.Add("PI_ROWID", OracleDbType.Varchar2, 40).Value = txtRowID.Text;
oCmd.Parameters.Add(new OracleParameter("PIO_CURSOR", OracleDbType.RefCursor)).Direction = ParameterDirection.Output;
oCmd.ExecuteNonQuery();
// clear the datagrid in preperation for loading
dgvStagingTable.Columns.Clear();
dgvStagingTable.Rows.Clear();
using (OracleDataReader MyReader = oCmd.ExecuteReader())
{
int ColumnCount = MyReader.FieldCount;
// add the column headers
DataGridViewColumn[] columns = new DataGridViewColumn[ColumnCount];
for (int i = 0; i < columns.Length; ++i)
{
DataGridViewColumn column = new DataGridViewTextBoxColumn();
column.FillWeight = 1;
column.HeaderText = MyReader.GetName(i);
column.Name = MyReader.GetName(i);
columns[i] = column;
}
dgvStagingTable.Columns.AddRange(columns);
// get the data and add the row
while (MyReader.Read())
{
//get all row values into an array
object[] objCells = new object[ColumnCount];
MyReader.GetValues(objCells);
//add array as a row to grid
dgvStagingTable.Rows.Add(objCells);
}
}
The stack trace shows:
at Oracle.DataAccess.Types.DecimalConv.GetDecimal(IntPtr numCtx)
at Oracle.DataAccess.Client.OracleDataReader.GetDecimal(Int32 i)
at Oracle.DataAccess.Client.OracleDataReader.GetValue(Int32 i)
at Oracle.DataAccess.Client.OracleDataReader.GetValues(Object[] values)
So I can see why it's causing an error (it's assuming a decimal conversion); but how do I get round this?
I tried explicitly setting the type of the column before loading the data with:
dgvStagingTable.Columns["TR_THROUGHPUT_TIME_NO"].ValueType = typeof(string);
and several other typeofs, but nothing made any difference.
Any help appreciated.
I initially suggested using OracleDbTypeEx (http://download.oracle.com/docs/html/E15167_01/OracleParameterClass.htm#CHDJHDGE) to fix this for you, this was wrong so this is a new suggestion.
so what I did:
Create Table Testdecimalteable(
Acol number(10) ,
DecCol NUMBER(38,38)
);
/
Insert Into Testdecimalteable
Select level,Level/(power(2,level))
From Dual
Connect By Level < 100 ;
/
Create or replace Procedure Testprocdecimal(Crs OUT Sys_Refcursor)
AS
Begin
Open Crs For
Select *
FROM Testdecimalteable ;
END Testprocdecimal ;
Now this will get some data known to be beyond .net.
then the .net side:
OracleConnection _conn = new OracleConnection("" );
_conn.Open();
OracleCommand oCmd = new OracleCommand();
oCmd.CommandText = "Testprocdecimal";
oCmd.CommandType = CommandType.StoredProcedure;
oCmd.Connection = _conn;
OracleParameter crs = new OracleParameter();
crs.OracleDbType = OracleDbType.RefCursor ;
crs.Direction = ParameterDirection.Output;
crs.ParameterName = "crs";
oCmd.Parameters.Add(crs);
using (OracleDataReader MyReader = oCmd.ExecuteReader())
{
int ColumnCount = MyReader.FieldCount;
// get the data and add the row
while (MyReader.Read())
{
//MyReader.GetOracleValue(1).ToString()
Console.WriteLine(string.Format("{0}/{1}", MyReader.GetValue(0),MyReader.GetOracleValue(1).ToString() ));
}
}
This converts everything to string but it'll work.
http://download-east.oracle.com/docs/html/A96160_01/features.htm#1048038
I just looked over your initial query once again, you are calling the query twice:
oCmd.ExecuteNonQuery();
...
using (OracleDataReader MyReader = oCmd.ExecuteReader())
you don't need the ExecuteNonQuery; the ExecuteReader executes the sp

Categories

Resources