There is no Row at Position -1 - c#

I am receiving this sql error there is no row at position - 1.
This is what I have done.
void showData(int index)
{
Connection con = new OrderManager.Connection();
SqlDataAdapter sda = new SqlDataAdapter("Select * from [MasterDatabase].[dbo].[Neworder] Where OrderID = '" + TxtBox_OrderID.Text + "'", con.ActiveCon());
dt = new DataTable();
sda.Fill(dt);
TxtBox_OrderID.Text = dt.Rows[index][0].ToString();
ClearTextBoxes();
dataGridView1.Rows.Clear();
foreach (DataRow item in dt.Rows)
{
int n = dataGridView1.Rows.Add();
dataGridView1.Rows[n].Cells[0].Value = item["OrderID"].ToString();
dataGridView1.Rows[n].Cells[1].Value = item["Date"].ToString();
dataGridView1.Rows[n].Cells[2].Value = item["Customer_Name"].ToString();
dataGridView1.Rows[n].Cells[3].Value = item["ProductID"].ToString();
dataGridView1.Rows[n].Cells[4].Value = item["Product_Name"].ToString();
dataGridView1.Rows[n].Cells[5].Value = item["Product_Color"].ToString();
dataGridView1.Rows[n].Cells[6].Value = item["Product_PCs"].ToString();
dataGridView1.Rows[n].Cells[7].Value = item["Product_Cutting"].ToString();
dataGridView1.Rows[n].Cells[8].Value = item["Product_TotalYards"].ToString();
}
label12.Text = "Row Count: " + dt.Rows.Count.ToString();
}
I want to display only those records while navigating whose OrderID is equals to the order ID in the database.

I think your error happens on this line
TxtBox_OrderID.Text = dt.Rows[index][0].ToString();
this is not an SQL error but a simple index out of the bounds of the array.
For some reasons, when you try to use a row that is not included in the Rows collection of the datatable you get this error message instead of the less ambiguous IndexOutOfRangeException. This message comes if you pass some value for the index variable that is less than zero or bigger than the number of rows in the datatable dt.
You don't have any check on the number of rows returned by the query and thus is possible that your query doesn't return any record or simple the value of index is -1
void showData(int index)
{
Connection con = new OrderManager.Connection();
SqlDataAdapter sda = new SqlDataAdapter(".......", con.ActiveCon());
dt = new DataTable();
sda.Fill(dt);
// Protect the access to the rows collection of the table...
if(index < dt.RowsCount && index >= 0)
{
TxtBox_OrderID.Text = dt.Rows[index][0].ToString();
// the code that fills the datagrid
}
else
{
// Message for your user about a record not found
}
}
As a side note, please follow ASAP the advice given to parameterize your query. You will avoid Sql Injection and parsin problems

Related

Access value in OleDbDataApter

Using OleDbDataAdapter SQL query to search for secific entry in access database.
OleDbDataAdapter adapter1 = new OleDbDataAdapter(#"SELECT Gallery_Number FROM Paintings WHERE Painting Number = '" + searchString + "'", myDB);
searchString = Convert.ToString( adapter);
searchString returns System.Data.OleDb.OleDbDataAdapter and not a Gallery number.
I would like to know how to get the value of this adapter and put it into a textbox.
First of all, I'd use a Scalar for this, since you only return a single value.
OleDbCommand command = new OleDbCommand(queryString, connection);
command.Connection.Open();
int galeryNumber = (int)command.ExecuteScalar();
But let's take a look at your code:
DataSet galNum = new DataSet();
oledbAdapter.Fill(galNum);
int galeryNumber = int.Parse(ds.Tables[0].Rows[0].ItemArray[0].ToString());
The best way to gain access to a OleDbDataAdapter is by converting the result set into a `DataSet. Then you can iterate through this set.
for (i = 0; i <= ds.Tables[0].Rows.Count - 1; i++)
{
DataRow dr = ds.Tables[0].Rows[i]; //One result line in your set
//DataRow contains n columns
for (int i = 0; i < ds.Tables[0].Columns.Count; i++)
{
string someEntry = dr[i].ToString();
}
}

Update the First Row in a database C# mysql

My problem is that:
I want to Select one row from the database, The data should be arrange in expiry (the ones that are not yet expired and I don't want to limit it). The items that passed the current date must be left alone. And with all the same ITEMID lets say I00001.
Then after selecting I want to Update the first row of the database. if the quantity reaches 0 then it will go the next row to update and so on.
Here is my example
Here is the current database screenshot.
I want select the itemid where = I00001 and deduct 50.
Then it should look like this
Then I want to arrange based on the expiry as I mentioned above.
Select the first row.
Deduct the 50 from the quantity. (as I also mentioned above).
Here is my code:
for (int i = 0; i < dataGridView.Rows.Count; i++)
{
cmd = new MySqlCommand(#"SELECT * FROM inventory2 WHERE itemid = #itemid ORDER BY expiry ", sqlconnection);
cmd = new MySqlCommand(#"UPDATE inventory2 SET quantity = #quantity WHERE itemid = #itemid ORDER BY expiry)", sqlconnection);
sqlconnection.Open();
cmd.ExecuteNonQuery();
sqlconnection.Close();
}
I'm open for another suggestion in doing this. I hope you understand my problem. Thank you very much. I'm sorry I cannot send another screenshot.
Try this,
void UpdateQuantity() {
// your connection string
MySqlDataAdapter adp = new MySqlDataAdapter("Select * from table where ItemID = " + 13 + " Order BY expiry", cnn); // I have test db and I used it
DataTable dt = new DataTable();
adp.Fill(dt);
int deductNum = 50;
foreach (DataRow item in dt.Rows)
{
int value = (int)item["quantity"];
if (value >= deductNum) // if had enough stock we don't need to pass the next line
{
int result = value - deductNum;
item["quantity"] = result.ToString();
break; // so need to exit from loop
}
else
{
deductNum -= value; // else we deduct value count from deduction
item["quantity"] = 0; // quantity finished so it will be 0
}
}
MySqlCommandBuilder cmb = new MySqlCommandBuilder(adp);
adp.UpdateCommand = cmb.GetUpdateCommand();
adp.Update(dt);
dataGridView1.DataSource = dt; //to show the result
}
(You can calculate :))
Hope helps,

Dataset to xml Null Values

I have the code below, where from 3 tables I take the data and write an xml.
I want write (when a record column has null value) the column on the xml with null value. For example if (Category_name == Null ) to write on the xml (Null) Right now the code skip the column and don’t even have this column on the xml.
string xmlFileData = "";
string[] tables = new string[] { "category", "company", "config" };
string query;
xmlFileData += "<MyXml>";
SqlConnection conn;
dbconnect obj;
obj = new dbconnect();//initailizing class object
for (int i = 0; i < tables.Length; i++)
{
string ifemptquery;
DataSet ds = new DataSet();
DataSet ds1 = new DataSet();
conn = obj.getConnection(); //calling connection function
ifemptquery = "SELECT * FROM " + tables[i] ";
SqlCommand cmd1 = new SqlCommand(ifemptquery, conn);
conn.Open();
SqlDataAdapter da1 = new SqlDataAdapter(cmd1);
DataTable dt1 = new DataTable();
da1.Fill(dt1);
conn.Close();
if (dt1.Rows.Count > 0)
{
query = "SELECT * FROM " + tables[i] ";
SqlCommand cmd = new SqlCommand(query, conn);
conn.Open();
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(ds);
conn.Close();
conn.Dispose();
ds.DataSetName = tables[i];
string vartbname = tables[i];
string trimed_tbname = vartbname.Replace("_", "");
ds.Tables[0].TableName = trimed_tbname;
xmlFileData += ds.GetXml();
}
else
{
}
}
xmlFileData += "</MyXml>";
File.WriteAllText(Server.MapPath("~/xmlbackup/") + "Backup.xml", xmlFileData);
I have been searching the whole world for a solution of writing null fields to XML using DataSet.WriteXML(). The answer posted by Vlad is the one I also used in my project but I found that following works in a much more performance optimized way. I have created a function for your convenience. Change your dataset tables one after the other by calling the following function and replacing the tables.
private DataTable GetNullFilledDataTableForXML(DataTable dtSource)
{
// Create a target table with same structure as source and fields as strings
// We can change the column datatype as long as there is no data loaded
DataTable dtTarget = dtSource.Clone();
foreach (DataColumn col in dtTarget.Columns)
col.DataType = typeof(string);
// Start importing the source into target by ItemArray copying which
// is found to be reasonably fast for nulk operations. VS 2015 is reporting
// 500-525 milliseconds for loading 100,000 records x 10 columns
// after null conversion in every cell which may be usable in many
// circumstances.
// Machine config: i5 2nd Gen, 8 GB RAM, Windows 7 64bit, VS 2015 Update 1
int colCountInTarget = dtTarget.Columns.Count;
foreach (DataRow sourceRow in dtSource.Rows)
{
// Get a new row loaded with data from source row
DataRow targetRow = dtTarget.NewRow();
targetRow.ItemArray = sourceRow.ItemArray;
// Update DBNull.Values to empty string in the new (target) row
// We can safely assign empty string since the target table columns
// are all of string type
for (int ctr = 0; ctr < colCountInTarget; ctr++)
if (targetRow[ctr] == DBNull.Value)
targetRow[ctr] = String.Empty;
// Now add the null filled row to target datatable
dtTarget.Rows.Add(targetRow);
}
// Return the target datatable
return dtTarget;
}
Refer similar question here - dataSet.GetXml() doesn't return xml for null or blank columns
Apart from solutions mentioned there, you can also traverse through dataset and write XML using XmlTextWriter. This method is not recommended if you are dealing with huge data.

multiple input from users to save in database in one column

I don't know how to describe what I am looking for but i can illustrate it with diagram which I drawn.
The first below here is 'user input' which will be in gridview and it will require users to input details. the (textbox) is a textbox and the details next to it is an input example.
User Inputs:
Items Quantity Unit Price Total
(textBox)abc (textBox)2 (textBox) 100 (textBox) 200
(textBox)def (textBox)1 (textBox) 150 (textBox) 150
After save button is clicked (I didn't show the button, sorry), the details will be saved in the database such as shown below 'save in database'.
Save in Database:
ID Items Quantity UnitPrice Total
10001 Abc , def 2,1 100,150 200,150
And when the user wants to display the details, the details should show like in the below 'display results'.
Display Results:
ID:10001
Items Quantity Unit Price Total
Abc 2 100 200
def 1 150 150
I hope this explanation is understandable, I am quite poor in explaining and also in ASP.
please help me to code this out in C# or VB because I am out of option to do this.
thank you so much.
code example:
string sql = "INSERT INTO Products(Name, ProductImage, OriginalPrice, DiscountPrice, Descriptions,StockQuantity, Category) VALUES (#Name, #ProdImage, #OriPrice, #DisPrice, #Descrp, #Quantity, #Category)";
try
{
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
SqlParameter[] param = new SqlParameter[7];
param[0] = new SqlParameter("#Name", SqlDbType.VarChar,100);
param[1] = new SqlParameter("#ProdImage", SqlDbType.VarChar, 100);
param[2] = new SqlParameter("#OriPrice", SqlDbType.Float );
param[3] = new SqlParameter("#DisPrice", SqlDbType.Float );
param[4] = new SqlParameter("#Descrp", SqlDbType.VarChar,50);
param[5] = new SqlParameter("#Quantity", SqlDbType.Int);
param[6] = new SqlParameter("#Category", SqlDbType.VarChar,50);
param[0].Value = name;
param[1].Value = image;
param[2].Value = OriPrice;
param[3].Value = disPrice;
param[4].Value = description;
param[5].Value = quantity;
param[6].Value = Category;
for (int i = 0; i < param.Length; i++)
{
cmd.Parameters.Add(param[i]);
}
cmd.CommandType = CommandType.Text;
cmd.ExecuteNonQuery();
current code:
private string CreateRow(DataTable data, Int32 index, String ColumnName)
{
String[] quan = data.Rows[0][ColumnName].ToString().Split(',');
if (quan.Length >= index)
return quan[index].ToString();
else
return "";
}
protected void GridView2_SelectedIndexChanged(object sender, EventArgs e)
{
SqlConnection conn = new SqlConnection("");
string sql = "SELECT * FROM SalesOrder WHERE ID = 10010";
DataSet DataFromDataBase = new DataSet();
SqlDataAdapter adp = new SqlDataAdapter("SELECT * FROM SalesOrder WHERE ID = 10010", conn);
adp.Fill(DataFromDataBase);
DataTable TempData = new DataTable();
TempData.Columns.Add("Quantity", typeof(string));
TempData.Columns.Add("UnitPrice", typeof(string));
for (Int32 i = 0; i < 5; i++)
{
DataRow row = TempData.NewRow();
row[0] = CreateRow(DataFromDataBase, i, "Quantity");
row[1] = CreateRow(DataFromDataBase , i, "UnitPrice");
TempData.Rows.Add(row);
}
}
DataFromDataBase is a datatable in which you are getting your data from database.
At last you'll get data in your required format in TempData Datatable.
you have to bind Grisview with TempData Datatable.
I have done this work with only two columns, you can change it according to your columns. I have taken maximum 5 as your maximum number of values in one field. you can modify according to your requirement.
DataTable TempData = new DataTable();
TempData.Columns.Add("Quantity", typeof(string));
TempData.Columns.Add("UnitPrice", typeof(string));
for (Int32 i = 0; i < 5; i++)
{
DataRow row = TempData.NewRow();
row[0] = CreateRow(DataFromDataBase, i, "Quantity");
row[1] = CreateRow(DataFromDataBase, i, "UnitPrice");
TempData.Rows.Add(row);
}
private string CreateRow(DataTable data, Int32 index, String ColumnName)
{
String[] quan = data.Rows[0][ColumnName].ToString().Split(',');
if (quan.Length >= index)
return quan[index].ToString();
else
return "";
}
If you are getting data in DataSet from database. you can pass parameter to CreateRow function as below
CreateRow( DataFromDataBase.Tables[0], i, "UnitPrice");
EDIT like this you have to get data in dataset or datatable (your choice)
DataSet DataFromDataBase = new DataSet();
SqlDataAdapter adp = new SqlDataAdapter("select * from tbdep;select * from tbemployee", ConfigurationManager.ConnectionStrings["cn"].ConnectionString);
adp.Fill(DataFromDataBase);
the way you are saving the values is really unrealistic and denormalized.
you should save the values like:
ID Items Quantity UnitPrice Total
10001 Abc 2 100 200
10001 def 1 150 150
and you can use following query in sql:
select * from table where ID = 10001
It will return you two rows in datatable or dataset(whatever you use). you can easily bind it with any control like GridView, Repeater and Datalist.
By this way you can easily reduce you code to display data in your required format.
may it'll help you.
What you are trying to achieve is possible in code, but would require custom concatenation and splitting when reading and writing to storage.
However, I would suggest that you normalize your data and create 2 tables:
IdHeader
HeaderId
CreatedOn
UserName
etc
IdDetail
HeaderId
Item
Quantity
UnitPrice
Total
etc
If you want them under the same ID why not add another column, say OrderId?

Pulling a SELECT query into a datatable and accessing it

I'm writing a small ASP.net C# web page and it keeps giving me an error stating:
There is no row at position 0.
I'm probably doing it wrong but here is some of my code:
string SqlQuery = "SELECT * ";
SqlQuery += " FROM main_list";
SqlQuery += " WHERE ID = #FindID";
SqlConnection conn = new SqlConnection("server=???;database=contacts;User
ID=???;Password=???;");
conn.Open();
SqlCommand SqlCmd = new SqlCommand(SqlQuery, conn);
SqlCmd.Parameters.Add("#FindID",searchID);
SqlDataAdapter da = new SqlDataAdapter(SqlCmd);
try {
da.Fill(dt);
fillData(p);
}
catch {
txtId.Text = "ERROR";
}
And FillData is the following:
protected void fillData(int pos) {
txtId.Text = dt.Rows[pos]["ID"].ToString();
txtCompany.Text = dt.Rows[pos]["Company"].ToString();
txtFirstName.Text = dt.Rows[pos]["First_Name"].ToString();
txtLastName.Text = dt.Rows[pos]["Last_Name"].ToString();
txtAddress1.Text = dt.Rows[pos]["Address1"].ToString();
txtAddress2.Text = dt.Rows[pos]["Address2"].ToString();
txtCity.Text = dt.Rows[pos]["City"].ToString();
txtState.Text = dt.Rows[pos]["State"].ToString();
txtZipCode.Text = dt.Rows[pos]["ZipCode"].ToString();
txtPhoneNum1.Text = dt.Rows[pos]["Phone_Num"].ToString();
txtPhoneNum2.Text = dt.Rows[pos]["Phone_Num2"].ToString();
txtFax.Text = dt.Rows[pos]["Fax_Num"].ToString();
txtEmail.Text = dt.Rows[pos]["Email"].ToString();
txtNotes.Text = dt.Rows[pos]["Notes"].ToString();
txtCategory.Text = dt.Rows[pos]["Category"].ToString();
txtSubCategory.Text = dt.Rows[pos]["SubCategory"].ToString();
txtDateAdded.Text = dt.Rows[pos]["DateAdded"].ToString();
txtDateModified.Text = dt.Rows[0]["DateModified"].ToString();
}
Here is the call that errors out:
protected void btnPrev_Click(object sender, EventArgs e) {
p--;
lblPage.Text = p.ToString();
fillData(p-1);
}
protected void btnNext_Click(object sender, EventArgs e) {
p++;
lblPage.Text = p.ToString();
fillData(p-1);
}
I'm trying to cycle thru the Rows[0] to Rows[1] or however many there is but it gives me the error about no row at position 0 or position 1. It only fills once and then errors out.
EDIT:
I'm trying to access the second row returned by the database after already accessing one row already. For example: Rows[0] is accessible fine but then when I try to read Rows[1] it errors and says it doesn't have a row in position 1. I can revise the code to return Rows[1] and it works but when I try to access Rows[0] it breaks. This is why I pass the variable (p) to fillData so it can show only that Rows value. Thanks!
EDIT 2: I believe it's because there is a postback that wipes the values retrieved by the database. Is there a way to get the database entries to stay even after a postback? If not I am guessing I will have to query the database every time.
The error message indicates there are no rows being returned by SQL. Are you sure there is data to be returned.
When you use dt.Rows[0] you are effectively saying "take the first row that comes back, and get a value from it." If the DataTable doesn't have any rows (i.e. your SQL query returns no matches), that's like saying "Here is a plate that contains no apples. Take the first apple and tell me what colour it is" - see? Doesn't make sense.
What you should do is check whether there are any rows before you try to read them...
if(dt.Rows.Count > 0)
{
// do stuff here.
}
Use Linq and a stored procedure it is much nicer
datacontext context = new datacontext();
var result = context.MyStoredProc(searchID).FirstOrDefault();
Try changing
SqlCmd.Parameters.Add("#FindID",searchID);
to
SqlCmd.Parameters.AddWithValue("#FindID",searchID);
Check your query on your database, make sure rows are actually being returned. Also, it's bad practice to put your query directly into your code like that, especially when using parameters. You might want to try something like this:
private Int32 CallStoredProcedure(Int32 FindId)
{
using (var dt = new DataTable())
{
using (var conn = new SqlConnection(ConnectionString))
{
using (var sqlCmd = new SqlCommand("SEL_StoredProcedure", conn))
{
using (var sda = new SqlDataAdapter(sqlCmd))
{
sqlCmd.CommandType = System.Data.CommandType.StoredProcedure;
sqlCmd.Parameters.AddWithValue("#FindId", FindId);
sqlCmd.Connection.Open();
sda.Fill(dt);
}
}
}
if (dt.Rows.Count == 1)
return Convert.ToInt32(dt.Rows[0]["ID"]);
else if (dt.Rows.Count > 1)
throw new Exception("Multiple records were found with supplied ID; ID = " + studentId.ToString());
}
return 0;
}
To set up your stored procedure, on your database run this:
CREATE procedure [dbo].[SEL_StoredProcedure]
#FindId int = null
as
SELECT * FROM main_list where ID = #FindId
Just remove the index identifier from the code:
e.g.
txtId.Text = dt.Rows["ID"].ToString();

Categories