weird result with c# winForms array of Lists - c#

so I'm trying to store values in an array of Lists in C# winForms. In the for loop in which I make the sql statment, everything works fine: the message box outputs a different medication name each time.
for (int i = 0; i < numberOfMeds; i++)
{
queryStr = "select * from biological where medication_name = '" + med_names[i] + "' and patient_id = " + patientID.patient_id;
using (var conn = new SqlConnection(connStr))
using (var cmd = new SqlCommand(queryStr, conn))
{
conn.Open();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
medObject.medication_date = (DateTime)rdr["patient_history_date_bio"];
medObject.medication_name = rdr["medication_name"].ToString();
medObject.medication_dose = Convert.ToInt32(rdr["medication_dose"]);
medsList[i].Add(medObject);
}
}
conn.Close();
MedicationTimelineClass medObjectx = medsList[i][0] as MedicationTimelineClass;
MessageBox.Show(medObjectx.medication_name);
}
}
but then, when I take the message box code out of the loop, meaning that the array of Lists is supposed to be populated, I always get the same value: the last value entered. the same medication name, no matter what number I put between those brackets. It's like if the whole array of Lists is populated with the same data.
for (int i = 0; i < numberOfMeds; i++)
{
queryStr = "select * from biological where medication_name = '" + med_names[i] + "' and patient_id = " + patientID.patient_id;
using (var conn = new SqlConnection(connStr))
using (var cmd = new SqlCommand(queryStr, conn))
{
conn.Open();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
medObject.medication_date = (DateTime)rdr["patient_history_date_bio"];
medObject.medication_name = rdr["medication_name"].ToString();
medObject.medication_dose = Convert.ToInt32(rdr["medication_dose"]);
medsList[i].Add(medObject);
}
}
conn.Close();
}
}
MedicationTimelineClass medObjectx = medsList[0][0] as MedicationTimelineClass;
MessageBox.Show(medObjectx.medication_name);
what's going on here?

It looks like you are reusing the same MedicationTimelineClass object inside your loop. Remember that your class is a reference type. You are basically adding the same reference to your list and updating the values of the properties stored in the object at that reference. Ultimately, all of the "items" in your list refer to the same object.
Instantiate a new MedicationTimelineClass object with each iteration and then add that new object to your list.

In the "while (rdr.Read())" loop, you're just adding the same object (medObject) to the list each time. The list is being populated with the same object, over and over again.

Related

OleDbCommand with 'where in' and dbParameter

I try to delete some rows from a table in an access database file via C#.
This attempt fails with no error which leads me to the conclusion that I have a valid query with incorrect data.
I tried to see if I can query the data with a select statement from my code and I can narrow the problem down to the parameters.
The statement should look as follows
SELECT * FROM tbIndex where pguid in ('4a651816-e15b-4c6a-85c4-74033ca6c423', '0add7bff-a22f-4238-9c7f-e1ff4ed3c7e2', '742fae8b-2692-4a6f-802c-848fad570696', '5e6b65de-2403-4800-a47d-e57c7bd8e0a6')
I tried two different ways*(dbCmd2 and dbCmd3)* from which the first*(dbCmd2)* works but is, due to injection problems, not my prefered solution.
using (OleDbCommand dbCmd2 = new OleDbCommand { Connection = m_Connection })
{
dbCmd2.CommandText = "SELECT * FROM tbIndex where pguid in ("+pguid+")";
using (DbDataReader reader = dbCmd2.ExecuteReader())
{
List<object[]> readValuesFromIndex = new List<object[]>();
while (reader.Read())
{
//Point reached
object[] arr = new object[reader.VisibleFieldCount];
reader.GetValues(arr);
//...
}
reader.Close();
}
using (OleDbCommand dbCmd3 = new OleDbCommand { Connection = m_Connection })
{
dbCmd3.CommandText = "SELECT * FROM tbIndex where pguid in (#pguid)";
dbCmd3.Parameters.Add("#pguid", OleDbType.VarChar).Value = pguid;
using (DbDataReader reader = dbCmd3.ExecuteReader())
{
List<object[]> readValuesFromIndex = new List<object[]>();
while (reader.Read())
{
//Point not reached
object[] arr = new object[reader.VisibleFieldCount];
reader.GetValues(arr);
//...
}
reader.Close();
}
}
Note that pguid is set to "'4a651816-e15b-4c6a-85c4-74033ca6c423', '0add7bff-a22f-4238-9c7f-e1ff4ed3c7e2', '742fae8b-2692-4a6f-802c-848fad570696', '5e6b65de-2403-4800-a47d-e57c7bd8e0a6'".
I always thought that the second option would simply replace the parameter in a safe manner but this is obviously not the case.
My question is:
Why doesn't the second option return any values?
A parameter always is a single value.
An in clause requires multiple values, separated by comma's.
You can do something like the following to pass them like separate parameters:
string[] guids = pguid.Split(',');
string sqlin = "";
int paramno = -1;
foreach (var guid in guids)
{
parametercount ++;
sqlin = sqlin + "#Param" + (string)parametercount; + ","
}
dbCmd3.CommandText = "SELECT * FROM tbIndex where pguid in (" + sqlin.Substring(0, sqlin.Length-1) + ")";
for(int i = 0; i <= parametercount; i++){
dbCmd3.Parameters.Add("#Param" + (string)i, OleDbType.VarChar).Value = guids[i].Replace("'", "");
}

c# SqlDataReader repeating final row of data

I'm using an SqlDataReader to read to a collection of custom type , but all I'm getting is the final row of the DataTable repeated, rather than a full table of information. Help would be gratefully received.
using (connection)
{
using (SqlCommand command = new SqlCommand(query, connection))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
lineData.Column1 = reader.GetValue(0).ToString();
lineData.Column2 = reader.GetValue(1).ToString();
lineData.Column3 = reader.GetValue(2).ToString();
lineData.Column4 = reader.GetValue(3).ToString();
lineData.Column5 = reader.GetValue(4).ToString();
lineData.Column6 = reader.GetValue(5).ToString();
lineData.Column7 = reader.GetValue(6).ToString();
lineData.Column8 = reader.GetValue(7).ToString();
columnData.Add(lineData);
}
}
}
}
foreach (var item in columnData)
{
Label.Text += item.Column1.ToString() + item.Column2.ToString() + item.Column3.ToString() + item.Column7.ToString();
}
lineData should be declared within while loop. If it was declared before the code you uploaded, then you're referencing the same instance for every data row.
Try change code to following;
while (reader.Read())
{
lineData = new LineData();//like that
lineData must be declared during the cycle at that time. If it is declared before the code you uploaded, you to the same instance for each row of data. Try to change the code on the following;

Get Data from Mysql Database to array in C# array out of bounds

I connect mysql database, then I get the x row. And when I try to the push the array the system got error. I dont understand this problem.
I tried this code. But I got error like array out of bonds...
int uz = b();// this func. get row number on the table
int[] userData = new int[uz];
MySqlConnection bag = new MySqlConnection(connstring);
MySqlCommand cmd = new MySqlCommand("Select readerid From readers",bag);
bag.Open();
MySqlDataReader oku = cmd.ExecuteReader();
oku.Read();
for (int i = 0; i <= uz; i++) {
userData[i] = Convert.ToInt32(oku[i]);
listBox1.Items.Add(userData[i]);
}
bag.Close();
I think you should use i < uz instead of i <= uz.
for (int i = 0; i < uz; i++)
EDIT:
Based on your comment I think you can try this:
List<int> userData = new List<int>();
MySqlConnection bag = new MySqlConnection(connstring);
MySqlCommand cmd = new MySqlCommand("Select readerid From readers",bag);
bag.Open();
MySqlDataReader oku = cmd.ExecuteReader();
while (oku.Read())
{
int current = Convert.ToInt32(oku["readerid"]);
userData.Add(current);
listBox1.Items.Add(current);
}
Dont forget to close the connections after you dont need them.
It looks like the main problem is that you believed oku[i] would give you data from the row at index i. What it really does is give you data from the column at index i for the current row. However, there were several other issues with the original code as well.
This should point you in a better direction:
var userData = new List<int>();
using (var bag = new MySqlConnection(connstring))
using (var cmd = new MySqlCommand("Select readerid From readers",bag))
{
bag.Open();
using (MySqlDataReader oku = cmd.ExecuteReader())
{
while (oku.Read())
{
userData.Add(oku[0]);
//userData.Add(oku["readerid"]); //would also work
}
}
}

Get Names ForEach Checked item in Checkedlistbox

I want to get the names associated with the states i select in my program. Below is the code that i currently have. My database has multiple locations within a state that have different contacts. I just want to select a state and acquire everyone under that state. Thanks for the help!
con = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=F:\\Database\\LocNo.accdb");
con.Open();
foreach (Object c in checkedListBox2.CheckedItems)
{
if (checkedListBox2.GetItemCheckState(checkedListBox2.Items.IndexOf(c)) == CheckState.Checked)
{
str1 += c.ToString() + ",";
flag = 1;
}
}
i = 0;
allSelectedtypestring = "";
allSelected = str1.Split(',');
while (allSelected.Length - 1 > i)
{
str = "select c1 from table where state ='" + allSelected[i++] + "'";
cmd = new OleDbCommand(str, con);
dr = cmd.ExecuteReader();
dr.Read();
allSelectedtypestring += dr.GetString(11);
}
label30.Text = Convert.ToString(allSelectedtypestring);
con.Close();
You can use the following code to retrieve the contacts:
var states = new List<string>();
foreach (Object c in checkedListBox2.CheckedItems)
{
states.Add(c.ToString());
flag = 1; // Can also be substituted by states.Count > 0
}
using(var con = new OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=F:\\Database\\LocNo.accdb"))
{
con.Open();
using(var cmd = con.CreateCommand())
{
var paramIndex = 0;
var paramClause = new System.Text.StringBuilder(100);
foreach(var state in states)
{
if (paramClause.Length > 0)
paramClause.Append(", ");
paramClause.Append("?");
var paramName = "State" + (paramIndex++).ToString();
cmd.Parameters.AddWithValue(paramName, state);
}
var paramsClause = string.Join(", ", cmd.Parameters.
cmd.CommandText = "select distinct c1 from table where state IN (" + paramsClause.ToString() + ")";
using(var rdr = cmd.ExecuteReader())
{
var contacts = new List<string>();
while(rdr.Read())
{
contacts.Add(rdr.GetString(0);
}
label30.Text = string.Join(", ", contacts);
}
}
}
Please note that I've made the following changes:
Added using statements to reliably dispose the connection, command and reader.
Used a List<string> as a more convenient way to collect the selected states.
Added DISTINCT to the SELECT in order to filter duplicate entries.
Used a parameter in the command text in order to avoid SQL injection attacks. Though this way to use a parameter with an IN clause works for SQL Server, I haven't checked whether it also works for an Access database. Let me know in the comments if it doesn't work.

extracting data from data set

Respected Users,
I am extracting data using data set.
I want to put value in textbox. But value is not comming.
I have following Code
try
{
da = new SqlDataAdapter("select ID from Customer where Name='" + gvBkPendingSearch.SelectedRows[0].Cells[1].Value.ToString() + "'",con);
DataSet ds = new DataSet();
da.Fill(ds);
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
txtCustomerID.Text = ds.Tables[0].Rows[0].ToString();
}
catch (Exception ex)
{
}
finally
{
}
txtCustomerID is my textbox.
It is capturing value as>>>>>System.Data.DataRow
Error is in txtCustomerID.Text = ds.Tables[0].Rows[0].ToString();
but i am not able to understand it.
Please help me.
change it like this
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
txtCustomerID.Text = ds.Tables[0].Rows[i]["ID"].ToString();
The mistake you are doing is, you are accessing this
ds.Tables[0].Rows[0].ToString();
means 0th row, the whole row!! not the column value
And the datatable row is System.Data.DataRow in .Net
You need to select the column:
txtCustomerID.Text = ds.Tables[0].Rows[i][0].ToString();
Also note that you are overwriting the value of the textbox on each iteration of the loop. So what you will end up with is the ID of the last record in this textbox.
Also your query seems vulnerable to SQL injection. Personally I would recommend you scraping the DataSets in favor of an ORM or even plain old ADO.NET:
public static IEnumerable<int> GetIds(string name)
{
using (var conn = new SqlConnection("Your connection string comes here"))
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = "select ID from Customer where Name=#Name";
cmd.Parameters.AddWithValue("#Name", name);
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
yield return reader.GetInt32(reader.GetOrdinal("ID"));
}
}
}
}
And now you could happily use this function:
string name = gvBkPendingSearch.SelectedRows[0].Cells[1].Value.ToString();
int id = GetIds(name).FirstOrDefault();
txtCustomerID.Text = id.ToString();

Categories

Resources