indexing Array out of Range Exception - c#

I try to save the SQL Results in a array and return it back. but i'm getting an exception: array out of range error.
here is my code:
public BookingUpdate[] getBookingUpdates(string token)
{
String command = "SELECT b.ID,b.VERANSTALTER, rr.VON ,rr.BIS, b.THEMA, b.STORNO, ra.BEZEICHNUNG from BUCHUNG b JOIN RESERVIERUNGRAUM rr on rr.BUCHUNG_ID = b.ID JOIN RAUM ra on ra.ID = rr.RAUM_ID WHERE b.UPDATE_DATE BETWEEN DATEADD (DAY , -20 , getdate()) AND getdate() AND b.BOOKVERNR = 0";
SqlConnection connection = new SqlConnection(GetConnectionString());
BookingUpdate[] bookingupdate = new BookingUpdate[1];
connection.Open();
try
{
SqlCommand cmd = new SqlCommand(command, connection);
SqlDataReader rdr = null;
int count = 0;
rdr = cmd.ExecuteReader();
while (rdr.Read())
{
DataTable dt = new DataTable();
dt.Load(rdr);
count = dt.Rows.Count;
for (int c = 0; c < count; c++)
{
bookingupdate = new BookingUpdate[c];
bookingupdate[c].bookingID = (long)rdr["ID"]; // <---- Error is here
bookingupdate[c].fullUserName = rdr["VERANSTALTER"].ToString();
bookingupdate[c].newStart = (DateTime)rdr["VON"];
bookingupdate[c].newStart = (DateTime)rdr["BIS"];
bookingupdate[c].newSubject = rdr["THEMA"].ToString();
bookingupdate[c].newlocation = rdr["BEZEICHNUNG"].ToString();
if (rdr["STORNO"].ToString() != null)
{
bookingupdate[c].deleted = true;
}
else
{
bookingupdate[c].deleted = false;
}
}
}
}
catch (Exception ex)
{
log.Error(ex.Message + "\n\rStackTrace:\n\r" + ex.StackTrace);
}
finally
{
connection.Close();
}
return bookingupdate;
}
What am i missing?

bookingupdate = new BookingUpdate[c];
bookingupdate[c].bookingID = (long)rdr["ID"];
you are creating an Array of length c, which means it has the Indexes 0 to (c-1) - and then you are out of bounds, when trying to store at Position c.

You appear to be creating and allocating memory for an array with
bookingupdate = new BookingUpdate[c];
but not actually creating instances of BookingUpdate. When you attempt to set properties on your array element there is no actual BookingUpdate to update - there is only a holder for one.
I'd suggest changing your code to something along the lines of:
...
bookingupdate = new BookingUpdate[count]; // allocates space for the number of BookingUpdates to be created
for (int c = 0; c < count; c++)
{
bookingupdate[c] = new BookingUpdate(); // create a new instance of BookingUpdate and assign it the array
bookingupdate[c].bookingID = (long)rdr["ID"];
...
I hope that this helps!

Imho i would simplify your way to construct that array with Linq:
BookingUpdate[] bookingupdate = dt.AsEnumerable()
.Select(r => new BookingUpdate{
bookingID = r.Field<long>("ID"),
fullUserName = r.Field<string>("VERANSTALTER"),
newStart = r.Field<DateTime>("Von"),
newEnd = r.Field<DateTime>("Bis"), // here was another bug in your originalcode
newSubject = r.Field<string>("THEMA"),
newlocation = r.Field<string>("BEZEICHNUNG"),
deleted = r.Field<string>("STORNO") != null
})
.ToArray();
On this way you will not have problems with arrays that are out of bounds.

You accessing the n'th element of an n-Elements array which is out of range, you need to access the n - 1 element.
bookingupdate = new BookingUpdate[c]; // You create an array of 5 elements for example
bookingupdate[c].bookingID = (long)rdr["ID"]; // Here you access the 5th elements but there are only 4

the problem is related with the size of the array;
for (int c = 0; c < count; c++)
{
bookingupdate = new BookingUpdate[c];
bookingupdate[c].bookingID = (long)rdr["ID"];
in the previous code, you are creating an array (bookingupdate ) of size 0 at first; then you are trying to insert an item. Even if you somehow manage to skip first one, it will again fail. Just update these lines to the following;
bookingupdate = new BookingUpdate[count];
for (int c = 0; c < count; c++)
{
bookingupdate[c].bookingID = (long)rdr["ID"];

for (int c = 0; c < count; c++)
{
bookingupdate = new BookingUpdate[c];
Error is at first iteration of this for loop where c is zero. ie, you are trying to create a array of length zero. bookingupdate = new BookingUpdate[0];

You have initialized an array but not the class itself before calling it. Also your initialization is wrong
count = dt.Rows.Count;
bookingupdate = new BookingUpdate[count];
for (int c = 0; c < count; c++)
{
bu = new BookingUpdate();
bu.bookingID = (long)rdr["ID"]; // <---- Error is here
bu.fullUserName = rdr["VERANSTALTER"].ToString();
bu.newStart = (DateTime)rdr["VON"];
bu.newStart = (DateTime)rdr["BIS"];
bu.newSubject = rdr["THEMA"].ToString();
bu.newlocation = rdr["BEZEICHNUNG"].ToString();
if (rdr["STORNO"].ToString() != null)
{
bu.deleted = true;
}
else
{
bu.deleted = false;
}
bookingupdate[c] = bu;
}

Arrays has zero based index.
When you create bookingupdate = new BookingUpdate[c]; your last index would c-1.
You can't access BookingUpdate[c] because it is not exist.
Let's say c = 4, that means we definedan array with 4 elements which they are;
BookingUpdate[0]
BookingUpdate[1]
BookingUpdate[2]
BookingUpdate[3]
BookingUpdate[c] would equal BookingUpdate[4] which there is no such an index.
From MSDN page;
Arrays are zero indexed: an array with n elements is indexed from 0 to
n-1.

Use this code
public BookingUpdate[] getBookingUpdates(string token)
{
String command = "SELECT b.ID,b.VERANSTALTER, rr.VON ,rr.BIS, b.THEMA, b.STORNO, ra.BEZEICHNUNG from BUCHUNG b JOIN RESERVIERUNGRAUM rr on rr.BUCHUNG_ID = b.ID JOIN RAUM ra on ra.ID = rr.RAUM_ID WHERE b.UPDATE_DATE BETWEEN DATEADD (DAY , -20 , getdate()) AND getdate() AND b.BOOKVERNR = 0";
BookingUpdate[] bookingupdate;
SqlConnection connection = new SqlConnection(GetConnectionString());
connection.Open();
try
{
SqlCommand cmd = new SqlCommand(command, connection);
SqlDataReader rdr = null;
int count = 0;
rdr = cmd.ExecuteReader();
while (rdr.Read())
{
DataTable dt = new DataTable();
dt.Load(rdr);
count = dt.Rows.Count;
bookingupdate = new BookingUpdate[count];
for (int c = 0; c < count; c++)
{
bookingupdate[c].bookingID = (long)rdr["ID"]; // <---- Error is here
bookingupdate[c].fullUserName = rdr["VERANSTALTER"].ToString();
bookingupdate[c].newStart = (DateTime)rdr["VON"];
bookingupdate[c].newStart = (DateTime)rdr["BIS"];
bookingupdate[c].newSubject = rdr["THEMA"].ToString();
bookingupdate[c].newlocation = rdr["BEZEICHNUNG"].ToString();
if (rdr["STORNO"].ToString() != null)
{
bookingupdate[c].deleted = true;
}
else
{
bookingupdate[c].deleted = false;
}
}
}
}
catch (Exception ex)
{
log.Error(ex.Message + "\n\rStackTrace:\n\r" + ex.StackTrace);
}
finally
{
connection.Close();
}
return bookingupdate;
}

Related

How to add two selectedindices for two listboxes to method that uses type table for handling multiple listbox parameters

I'm trying to fetch a dataset that uses two list boxes for building the query. How to write?
public void LoadChecklist(Object sender, System.EventArgs e)
{
string strConnString = System.Configuration.ConfigurationManager.ConnectionStrings["SQLDEV1"].ConnectionString;
var SearchResultsTable = new DataTable();
using (var con = new SqlConnection(strConnString))
{
using (var cmd = new SqlCommand("sp_get_QUADRA_CHECKLIST", con))
{
cmd.CommandType = CommandType.StoredProcedure;
using (var adapter = new SqlDataAdapter(cmd))
{
using (var dtSIPA = new DataTable())
{
//dtSIPA.Columns.Add("Id", typeof(int));//assuming you are looking for a list of int values
dtSIPA.Columns.Add("SIPA", typeof(string));
dtSIPA.Columns.Add("RO", typeof(string));
int[] yourSelectedIndexes = ddlSIPA.GetSelectedIndices();
int[] yourSelectedIndexes2 = lbRO.GetSelectedIndices();
for (int i = yourSelectedIndexes.Length - 1; i >= 0; i--)
{
dtSIPA.Rows.Add(ddlSIPA.Items[yourSelectedIndexes[i]].Value);
}
for (int j = yourSelectedIndexes2.Length - 1; j >= 0; j--)
{
dtSIPA.Rows.Add(lbRO.Items[yourSelectedIndexes[j]].Value);
}
//if (SearchResultsTable.Rows.Count >= 0)
//{
cmd.Parameters.Add("#AP_DEV", SqlDbType.Bit).Value = CbAPDev.Checked;
cmd.Parameters.Add("#PROD_DEV", SqlDbType.Bit).Value = cbProdDev.Checked;
cmd.Parameters.Add("#ROTYPE", SqlDbType.NVarChar, 255).Value = ddlROTYPE.SelectedItem.Value;
cmd.Parameters.Add("#SIPA", SqlDbType.Structured).Value = dtSIPA;
cmd.Parameters.Add("#RO", SqlDbType.Structured).Value = dtSIPA;
//Response.Write(dtSIPA);
//}
//else
//{ ScriptManager.RegisterStartupScript(this, GetType(), "showalert", "alert('Selections not found!');", true); }
}
try
{
adapter.Fill(SearchResultsTable);
GV1.DataSource = SearchResultsTable;
GV1.DataBind();
}
catch (System.Data.SqlClient.SqlException ex)
{
Response.Write(ex);
}
}
}
}
I should get a dataset back filtered to the selections made in the two list boxes ddlSIPA and lbRO but I'm sure I don't have the code right.
Exception Details: System.IndexOutOfRangeException: Index was outside the
bounds of the array.
Line 571: for (int j =
yourSelectedIndexes2.Length - 1; j >= 0; j--)
Line 572: {
Line 573: dtSIPA.Rows.Add(lbRO.Items
[yourSelectedIndexes[j]].Value);
Line 574: }
Line 575:
Source File: \sw.nos.boeing.com\ewh\dev\VOL01\vanity\qualityvisibility\QUADRA\SAVE_ASSESSMENT.aspx.cs Line: 573
USE [VISIBILITY_BOARD]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER On
GO
/* Create a table type. */
CREATE TYPE SIPA_TYPE AS TABLE
( SIPA NVARCHAR(255) NULL,
RO NVARCHAR(MAX) NULL);
GO
CREATE PROCEDURE [dbo].[sp_get_QUADRA_CHECKLIST] (#AP_DEV bit = '', #PROD_DEV bit = '', #ROTYPE nvarchar(255) = '', #SIPA AS SIPA_TYPE READONLY, #RO AS SIPA_TYPE READONLY) AS
SELECT '' AS QUES_ANSWER
, '' AS COMMENTS
, cl.RO_TYPE
, cl.RO
, cl.QUES_ID
, cl.DFQRO AS QDRO
, cl.QUADRA_QUES
FROM Tbl_QUADRA_CL cl
WHERE (cl.SIPA IN(SELECT SIPA FROM #SIPA) OR (SELECT COUNT(SIPA) FROM #SIPA) = 0)
AND (cl.RO IN(SELECT RO FROM #RO) OR (SELECT COUNT(RO) FROM #RO) = 0)
AND (cl.RO_TYPE = #ROTYPE OR #ROTYPE IS NULL)
AND (cl.AP_DEV = #AP_DEV OR #AP_DEV IS NULL)
AND (cl.PROD_DEV = #PROD_DEV OR #PROD_DEV IS NULL)
GROUP BY
cl.RO_TYPE
, cl.RO
, cl.QUES_ID
, cl.DFQRO
, cl.QUADRA_QUES
I found an error.
dtSIPA.Columns.Add("SIPA", typeof(string));
dtSIPA.Columns.Add("RO", typeof(string));
int[] yourSelectedIndexes = ddlSIPA.GetSelectedIndices();
int[] yourSelectedIndexes2 = lbRO.GetSelectedIndices();
for (int i = yourSelectedIndexes.Length - 1; i >= 0; i--)
{
dtSIPA.Rows.Add(ddlSIPA.Items[yourSelectedIndexes[i]].Value);
}
for (int j = yourSelectedIndexes2.Length - 1; j >= 0; j--)
{
dtSIPA.Rows.Add(lbRO.Items[yourSelectedIndexes[j]].Value);
}
You are adding two columns here, SIPA and RO but while adding rows for these columns, you are adding the rows separately.
First off the number of selections in the two list boxes ddlSIPA and lbRO should be the same. Only then can they be added together in a single row.
Your code adds the values of ddlSIPA and bRO as separate rows instead of a single row. Your code should be something like this
dtSIPA.Columns.Add("SIPA", typeof(string));
dtSIPA.Columns.Add("RO", typeof(string));
int[] yourSelectedIndexes = ddlSIPA.GetSelectedIndices();// or lbRO.GetSelectedIndices(), they have to be same in count
int[] yourSelectedIndexes2 = lbRO.GetSelectedIndices();
for (int i = yourSelectedIndexes.Length - 1; i >= 0; i--)
{
dtSIPA.Rows.Add(ddlSIPA.Items[yourSelectedIndexes[i]].Value, lbRO.Items[yourSelectedIndexes2[i]].Value);
}
Two values have to be added for a single row instead of adding both values as rows.

Drawing a chart from a List of list in windows forms C#

I am trying to draw a stacked graph from my database. I have 10 comboboxes(drop down list). The user can select up to 10 attributes. The values are all double. The values should be normalized and averaged. Normalizing means to move the range of the values between 0 and 1. I get no errors from reading and calculations but when I am trying to draw the chart it gives me index error (out of range). I am not sure what I am doing wrong. Here is my whole code:
SqlCommand cmd = new SqlCommand(command, con);
SqlDataReader reader ;
SqlDataAdapter da = new SqlDataAdapter(cmd);
con.Open();
reader = cmd.ExecuteReader();
DataTable dt = new DataTable();
List<List<double>> list = new List<List<double>>();
List<double> inner;
List<double> Outdistance = new List<double>();
//reading the columns and storing them into list. the coulmns 0 and 2 are not needed.
while (reader.Read())
{
inner = new List<double>();
for(int i = 3;i<reader.FieldCount;i++)
{
var temp = reader.GetDouble(i);
inner.Add(temp);
}
list.Add(inner);
var temp2 = reader.GetDouble(1);
Outdistance.Add(temp2);
}
con.Close();
List<List<double>> normallist = new List<List<double>>();
List<double> AVGDist = average(Outdistance, 10);
//normalizing the data. data-min/range
foreach(List<double> l in list)
{
normallist.Add(normalizer(l));
}
List<List<double>> avgList = new List<List<double>>();
//reducing the amount by averaging every 10 element.
foreach (List<double> l in normallist)
{
avgList.Add(average(l,10));
}
//drawing the chart
foreach (List<double> lst in avgList)
{
Series S = new Series();
S.ChartType = SeriesChartType.StackedArea;
chart1.Series.Add(S);
for(int i = 0 ; i < lst.Count ; i++)
{
this.chart1.Series[S.Name].Points.AddXY(AVGDist[i],lst[i]);
}
}
public List<double> average(List<double> T , int n)
{
var currentElement = 0;
var currentSum = 0.0;
var newList = new List<double>();
foreach (var item in T)
{
currentSum += item;
currentElement++;
if (currentElement == n)
{
newList.Add(currentSum / n);
currentElement = 0;
currentSum = 0.0;
}
}
if (currentElement > 0)
{
newList.Add(currentSum / currentElement);
}
return newList;
}
public List<double> normalizer( List<double> T)
{
double min, max, range;
min = T.Min();
max = T.Max();
range = max - min;
for (int i = 0; i < T.Count;i++ )
{
T[i] = (T[i] - min) / range;
}
return T;
}
I also checked my select string but it was correct. I think I am not using the correct code for the charts. Can anyone please help?
The error should be thrown in the below line,
this.chart1.Series[S.Name].Points.AddXY(AVGDist[i],lst[i]);
Series has been indexed using S.Name. S.Name should be set to some string, before it can be accessed in the above line.
The code for your charts is correct. And looking at your code, it looks like the index for your AVGDist is going out of bounds in this line
this.chart1.Series[S.Name].Points.AddXY(AVGDist[i],lst[i]);
Add a breakpoint here to debug further.
for(int i=0; i < T.Count -1; i++) << I think the -1 is the problem add it and try.
public List<double> normalizer( List<double> T)
{
double min, max, range;
min = T.Min();
max = T.Max();
range = max - min;
for (int i = 0; i < T.Count -1;i++ )
{
T[i] = (T[i] - min) / range;
}
return T;
}

Dynamic listView Add x columns and x rows

This is my code:
sql = "SELECT * FROM stock";
cmd = new SQLiteCommand(sql, mdb);
SQLiteDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
var_depot = reader["depot"].ToString();
ajouterlistview1 = new ListViewItem(reader["id"].ToString());
ajouterlistview1.SubItems.Add(reader["article"].ToString());
listView1.Items.Add(ajouterlistview1);
listView1.Refresh();
for (int i = 0; i < listView1.Columns.Count; i++)
{
if (var_depot == listView1.Columns[i].Text)
{
for (int j = 0; j < listView1.Items.Count; j++)
{
/*if (listView1.Columns[i].Text == var_depot )
{*/
listView1.Items[j].SubItems[1].Text = reader["quantite"].ToString();
//}
}
}
}
}
This code work fine but when I change this line:
listView1.Items[j].SubItems[1].Text = reader["quantite"].ToString();
to this line :
listView1.Items[j].SubItems[i].Text = reader["quantite"].ToString();
I get a error because my row X is not defined :/
What should I do please?
It looks like you have more listView1.Columns than listView1.Items[...].SubItems. Add some empty subItems (ajouterlistview1.SubItems.Add("")) to make sure that you can have the access to listView1.Items[...].SubItems[i].Text.
Try this way:
for (int i = 0; i < listView1.Columns.Count; i++)
{
if (var_depot == listView1.Columns[i].Text)
{
ajouterlistview1.SubItems.Add(reader["quantite"].ToString());
break;
}
else
ajouterlistview1.SubItems.Add("");
}

Execute array values in query c#

I'm busy with a task program and then I came on to a problem!
Here is my code:
int id = 1;
List<Button> _bListGroups = new List<Button>();
MySqlCommand mcCommandUserID = new MySqlCommand("SELECT * FROM pakket WHERE gebruikersid=#id", _msConnection);
mcCommandUserID.Parameters.AddWithValue("#id", id);
MySqlDataReader msReader = mcCommandUserID.ExecuteReader();
DataTable dtGetUserid = new DataTable();
dtGetUserid.Load(msReader);
string[] nummer = new string[10];
int i = 0;
foreach (DataRow row in dtGetUserid.Rows)
{
nummer[i] = row["groepsid"].ToString();
i++;
}
MySqlCommand msCommandGetGroup = new MySqlCommand("SELECT * FROM groep WHERE id=#id",_msConnection);
msCommandGetGroup.Parameters.AddWithValue("#id", nummer[i]);
MySqlDataReader msGetGroup = msCommandGetGroup.ExecuteReader();
DataTable dtGetGroup = new DataTable();
dtGetGroup.Load(msGetGroup);
int mtop = 10;
int mleft = 15;
int count = 1;
foreach (DataRow dr in dtGetGroup.Rows)
{
Button temp = new Button();
temp.Name = "bt" + dr["id"];
temp.Text = (string)dr["groepsnaam"];
temp.Width = 125;
temp.Height = 125;
temp.Left = mleft;
temp.Top = mtop;
mleft += 127;
if (count == 2)
{
mtop += 125;
mleft = 15;
count = 0;
}
count++;
_bListGroups.Add(temp);
}
return _bListGroups.ToArray();
When i give my array a specific number(like nummer[1]) i get one button back but if I use the variable i, it doesn't give me any buttons. I already tried to debug it but I couldn't solve it.
Note that you are increasing i in the end of every iteration. So in the end i is greater than the last assigned index by 1. Therefore you need i-1:
msCommandGetGroup.Parameters.AddWithValue("#id", nummer[i-1]);
Also you might want to have some prechecks here for edge cases, say when there is no rows in dtGetUserid.Rows.
You've failed to reset your counter.
the variable i is at this stage:
msCommandGetGroup.Parameters.AddWithValue("#id", nummer[i]);
set to an array index which you havent allocated with any values.

Add only a percentage of rows to DataTable

So i'm making a program to Audit some of our workers randomly. And i'm trying to make a program to scan our Access DB and pull a percentage of orders. But i want to randomly select the orders, i dont want just the top 5% or something.
static DataTable RandomSelect(double errPercentage,string User)
{
OleDbConnection conn = new OleDbConnection(strAccessConn);
string query = "SELECT ControlNumber FROM Log WHERE User ='" + User + "' AND Log.EndStatus in ('Needs Review', 'Check Search', 'Vision Delivery', 'CA Review', '1TSI To Be Delivered');";
OleDbDataAdapter adapter = new OleDbDataAdapter(query, conn);
DataTable dt = new DataTable();
DataTable dtRandomRows = new DataTable();
try
{
adapter.Fill(dt);
//dtRandomRows = dt.Clone();
Random rDom = new Random();
int i = 0;
for (int ctr = 1; ctr <= dt.Rows.Count; ctr++)
{
i = rDom.Next(1, dt.Rows.Count);
//dtRandomRows.Rows.Add(dt.Rows[i]);
dtRandomRows.ImportRow(dt.Rows[i]);
}
dtRandomRows.AcceptChanges();
}
catch (OleDbException ex)
{
}
return dtRandomRows;
}
The code above works, but it randomly selects rows from the entire table of the ControlNumbers (orders) and puts them all into dtRandomRows. However, i just want this to select the 'errPercentage' or rows randomly...any thoughts?
Random rand = new Random();
// Mark every row as not selected yet.
int[] nonSelectedRows = new int[dt.Rows.Count];
for(int i = 0; i < dt.Rows.Count; i++)
nonSelectedRows[i] = 1;
int numSelected = 0;
int numLeft = dt.Rows.Count;
int targetNum = dt.Rows.Count * errPercentage;
while(numSelected < targetNum)
{
for (int row = 0; row < dt.Rows.Count; row++)
{
// Each record has a 1/numleft chance of getting selected.
boolean isSelected = rand.Next(numLeft) == 0;
// Check to make sure it hasn't already been selected.
if(isSelected && nonSelectedRows[row] > 0)
{
dtRandomRows.ImportRow(dt.Rows[row]);
nonSelectedRows[row] = -1; // Mark this row as selected.
numSelected++;
numLeft--;
}
// We've already found enough to match our targetNum.
if(numSelected >= targetNum)
break;
}
}

Categories