SqlDataReader read() working unconscionability - sql-server

im getting data from the server as expected as you can see here (the data is not null)
but it won't enter to while (reader.Read())
or sometimes after one or two iteration im getting the exception
"Data is Null. This method or property cannot be called on Null values."
again, the data is not null
EDIT: added some code snippet
System.Data.SqlClient.SqlConnection sqlConnection = null;
try
{
sqlConnection = connectToDB();
SqlCommand cmd = new SqlCommand(#"SELECT TOP 50 R.[RoundID] ,[DailyOrder] ,min(R.[RoundName]) as RoundName, min([EquipCode]) as TruckCode,
sum(RD.[Weight]) as [Weight], RD.BlilCode, min(Blil.BlilName) as BlilName
FROM [CVfeedDB].[dbo].[Planning.Rounds] as R
left join [CVfeedDB].[dbo].[Planning.RoundsDetail] as RD on R.RoundID = RD.RoundID
left join [CVfeedDB].[dbo].[constants.Blil] as Blil on RD.BlilCode = Blil.BlilCode
WHERE R.[ActionDate] = #ActionDate
Group by R.[RoundID] ,[DailyOrder], RD.BlilCode
order by [DailyOrder] ", sqlConnection);
cmd.CommandType = System.Data.CommandType.Text;
//string date = Convert.ToString();
var dt = DateTime.ParseExact(Variables().Item("Date Select").get_Value(0).ToString(), "dd/MM/yyyy", null);
var dt1 = dt.Date.ToString("yyyy-MM-dd");
cmd.Parameters.AddWithValue("#ActionDate",dt1 );
string prefix = "";
int i = 1;
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
prefix = ordersName + i.ToString() + "]";
List<object> list = new List<object>();
List<object> IDList = new List<object>();
int id = Convert.ToInt32(Variables().Item(prefix + ".LoopID").get_Value(0));
int k = reader.GetInt32(0);
if (id == 0 || id == k)//if no id or we are writing the same id
{
Variables().Item(prefix + ".LoopID").set_Value(0, reader.GetInt32(0));
//Variables().Item(prefix + ".").set_Value(0, reader.GetInt32(1)); //Order sequence
Variables().Item(prefix + ".LoopName").set_Value(0, reader.GetString(2));
Variables().Item(prefix + ".Truck").set_Value(0, Convert.ToInt32(reader.GetString(3)));
Variables().Item(prefix + ".Weight").set_Value(0, Convert.ToInt32(reader.GetDecimal(4)));
Variables().Item(prefix + ".MixID").set_Value(0, Convert.ToInt32(reader.GetString(5)));
Variables().Item(prefix + ".MixName").set_Value(0, reader.GetString(6));
}
please not that Variables().Item(...) it how I communicate with 3rd party software

First problem is that your SqlConnection is null. It will always return null value.
Secondally
You should check the reader has rows like i m using reader.Hasrows
System.Data.SqlClient.SqlConnection sqlConnection = null;
try
{
sqlConnection = connectToDB();
SqlCommand cmd = new SqlCommand(#"SELECT TOP 50 R.[RoundID] ,[DailyOrder] ,min(R.[RoundName]) as RoundName, min([EquipCode]) as TruckCode,
sum(RD.[Weight]) as [Weight], RD.BlilCode, min(Blil.BlilName) as BlilName
FROM [CVfeedDB].[dbo].[Planning.Rounds] as R
left join [CVfeedDB].[dbo].[Planning.RoundsDetail] as RD on R.RoundID = RD.RoundID
left join [CVfeedDB].[dbo].[constants.Blil] as Blil on RD.BlilCode = Blil.BlilCode
WHERE R.[ActionDate] = #ActionDate
Group by R.[RoundID] ,[DailyOrder], RD.BlilCode
order by [DailyOrder] ", sqlConnection);
cmd.CommandType = System.Data.CommandType.Text;
//string date = Convert.ToString();
var dt = DateTime.ParseExact(Variables().Item("Date Select").get_Value(0).ToString(), "dd/MM/yyyy", null);
var dt1 = dt.Date.ToString("yyyy-MM-dd");
cmd.Parameters.AddWithValue("#ActionDate",dt1 );
string prefix = "";
int i = 1;
SqlDataReader reader = cmd.ExecuteReader();
if(reader.HasRows)
{
while (reader.Read())
{
prefix = ordersName + i.ToString() + "]";
List<object> list = new List<object>();
List<object> IDList = new List<object>();
int id = Convert.ToInt32(Variables().Item(prefix + ".LoopID").get_Value(0));
int k = reader.GetInt32(0);
if (id == 0 || id == k)//if no id or we are writing the same id
{
Variables().Item(prefix + ".LoopID").set_Value(0, reader.GetInt32(0));
//Variables().Item(prefix + ".").set_Value(0, reader.GetInt32(1)); //Order sequence
Variables().Item(prefix + ".LoopName").set_Value(0, reader.GetString(2));
Variables().Item(prefix + ".Truck").set_Value(0, Convert.ToInt32(reader.GetString(3)));
Variables().Item(prefix + ".Weight").set_Value(0, Convert.ToInt32(reader.GetDecimal(4)));
Variables().Item(prefix + ".MixID").set_Value(0, Convert.ToInt32(reader.GetString(5)));
Variables().Item(prefix + ".MixName").set_Value(0, reader.GetString(6));
}
}
}

try this.
string namethestore = myReader.IsDBNull(namePos)
? string.Empty
: reader.GetString(reader.GetString(2));
Variables().Item(prefix + ".LoopName").set_Value(0, namethestore);

I have added isNull(rowname, 0 ) to the problematic rows and it solved my problem

Related

Can't update db using c# loop

Im trying to update rows in my table using loop, I get no error but nothing changed in my data...Thats my code.. What am I missing ?
private void updateZipInDB(List<ZipObj> zipCodeToUpdate)
{
var comm = "";
string DbConnString = ConfigurationManager.AppSettings["dbConnectionString"].ToString();
using (SqlConnection conn = new SqlConnection(DbConnString))
{
comm = "UPDATE Account SET address1_postalcode = #newVal WHERE AccountId = #accountID";
using (SqlCommand command = new SqlCommand(comm, conn))
{
conn.Open();
command.Parameters.AddWithValue("#newVal", "f");
command.Parameters.AddWithValue("#accountID", "f");
for (int i = 0; i < zipCodeToUpdate.Count; i++)
{
zipCodeToUpdate[i].NewVal + "' WHERE AccountId = '" + zipCodeToUpdate[i].AccountId + "'";
command.Parameters["#newVal"].Value = zipCodeToUpdate[i].NewVal;
command.Parameters["#accountID"].Value = zipCodeToUpdate[i].AccountId;
command.ExecuteNonQuery();
}
conn.Close();
}
}
}

Could i increase speed of executing statements?

My function: Removes the unit in a specific row of a given Table
private static void removeUnits(String connectionString, String tableName, String columnID, String columnToFix)
{
List<String> rowsToEdit = new List<String>();
using (SqlConnection connection = new SqlConnection(connectionString))
{
using (var command = connection.CreateCommand())
{
command.CommandText = "SELECT " + columnID + "," + columnToFix + " FROM " + tableName;
connection.Open();
using (var reader = command.ExecuteReader())
{
var indexOfR_MEASUREDVALUEID = reader.GetOrdinal(columnID);
var indexOfT_VALUE = reader.GetOrdinal(columnToFix);
while (reader.Read())
{
var t_value = reader.GetValue(indexOfT_VALUE);
var t_id = reader.GetValue(indexOfR_MEASUREDVALUEID);
String newValue = getWithoutUnit(t_value.ToString());
if (newValue != null)
{
String sql = "UPDATE " + tableName + " SET " + columnToFix + "='" +
newValue + "' WHERE " + columnID + "='" + t_id + "';";
rowsToEdit.Add(sql);
}
}
connection.Close();
}
}
Console.WriteLine("start writing " + rowsToEdit.Count + " entries?");
Console.ReadLine();
SqlCommand sqlCmd;
sqlCmd = new SqlCommand("", connection);
sqlCmd.Connection.Open();
foreach (String command in rowsToEdit)
{
sqlCmd.CommandText = command;
sqlCmd.ExecuteNonQuery();
}
}
Console.WriteLine(rowsToEdit.Count + " commands executed");
}
I am using C# in Visual Studio 2010 and SQL-Server 2012.
It works fine, but executing of 200000 lines takes really long.
Is its possible to do this faster?
My suggestion involves looking into parallelism:
Note: The code isn't tested, just typed it out in Notepad++
private static void removeUnits(String connectionString, String tableName, String columnID, String columnToFix)
{
List<new Tuple<object, object>> rowsToEdit = new List<new Tuple<object, object>>();
using (SqlConnection connection = new SqlConnection(connectionString))
{
using (var command = connection.CreateCommand())
{
command.CommandText = "SELECT " + columnID + "," + columnToFix + " FROM " + tableName;
connection.Open();
using (var reader = command.ExecuteReader())
{
var indexOfR_MEASUREDVALUEID = reader.GetOrdinal(columnID);
var indexOfT_VALUE = reader.GetOrdinal(columnToFix);
while (reader.Read())
{
rowsToEdit.Add(new Tuple<object, object>(reader.GetValue(indexOfT_VALUE),reader.GetValue(indexOfR_MEASUREDVALUEID)));
}
connection.Close();
}
}
}
// Use parallelism here
Parallel.Foreach(rowsToEdit, currentRow =>
{
String newValue = getWithoutUnit(currentRow.Value1.ToString());
if (newValue != null)
{
// reopen connection
// use parameters here, and call SP
}
}
Console.WriteLine("start writing " + rowsToEdit.Count + " entries?");
Console.ReadLine();
}
Stored Proc:
Create StoredProcedure MySP
(
#tablename varchar(50),
#columnToFix varchar(50),
#newValue varchar(50),
#columnID varchar(50),
#tID varhcar(varchar(50)
)
As
Begin
Declare #MySQL varchar(500)
Set #MySQL = 'Update ' + #tableName + ' Set ' + #columnToFix + ' = '' + #newValue + ''' + ' Where ' + #columnID + ' = '' + #tID + '''
sp_executesql #MySQL
End
It's important to note that dynamic sql is generally frowned down upon. Here's a link discussing dynamic sql (pros/cons):http://www.sommarskog.se/dynamic_sql.html
Also it's possible you may run into some locking/contention issues b/c you're hitting one table(based on the input parameters of the function).
First try to use Parameters as already mentioned in the comments. Second, use the SqlCommand.Prepare() statement. The actual speed also depends on your machine capacities (HD Write Speed/RAM). Here is the example (you may have to edit the SqlDbTypes according to your Colum Types)
private static void RemoveUnits(string connectionString, string tableName, string columnID, string columnToFix)
{
Dictionary<int, string> rowsToEdit = new Dictionary<int, string>();
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
using (SqlCommand command = connection.CreateCommand())
{
command.CommandText = "SELECT " + columnID + "," + columnToFix + " FROM " + tableName;
using (var reader = command.ExecuteReader())
{
var indexOfR_MEASUREDVALUEID = reader.GetOrdinal(columnID);
var indexOfT_VALUE = reader.GetOrdinal(columnToFix);
while (reader.Read())
{
string t_value = reader.GetString(indexOfT_VALUE);
int t_id = reader.GetInt32(indexOfR_MEASUREDVALUEID);
string newValue = getWithoutUnit(t_value);
if (newValue != null)
{
// save values in dictionary
rowsToEdit[t_id] = newValue;
}
}
}
}
Console.WriteLine("start writing " + rowsToEdit.Count + " entries?");
Console.ReadLine();
string updateCmd = "UPDATE " + tableName + " SET " + columnToFix + "= #Value WHERE " + columnID + "= #Key;";
using (SqlTransaction transaction = connection.BeginTransaction())
{
SqlCommand sqlCmd = connection.CreateCommand();
sqlCmd.CommandText = updateCmd;
sqlCmd.Parameters.Add("#Value", System.Data.SqlDbType.NVarChar, -1);
sqlCmd.Parameters.Add("#Key", System.Data.SqlDbType.Int);
// important for performance
sqlCmd.Prepare();
foreach (var update in rowsToEdit)
{
// change values of parameters
sqlCmd.Parameters["#Key"].Value = update.Key;
sqlCmd.Parameters["#Value"].Value = update.Value;
// and execute it
sqlCmd.ExecuteNonQuery();
}
transaction.Commit();
}
}
Console.WriteLine(rowsToEdit.Count + " commands executed");
}
Edit: if getWithoutUnit(string) does something not very complex, you could probably do your operation with a single statement using TSQL, which comes with various string manipulation capabilities. Like UPDATE TableName SET StringColumn = <string manipulation TSQL here>, see http://msdn.microsoft.com/en-us/library/ms181984.aspx
Edit2: added transaction from comment hint (indeed should be faster as well), strongly typed columns

Generate code with recursion

I'm having issue with creating product code in recursion.
What I want to do is:
I enter code 1000
-If code exist in database regenerateCode(string code)
-else insert into database
Code:
(...)
if(codeExist)
CodeTB.Text = regenerateCode(string toParse); //toParse = 1000
string regenerateCode(string toParse)
{
string helper = "";
int parseCode = int.Parse(toParse);
helper = new string('0', 4 - parseCode.ToString().Length);
helper += parseCode + 1;
using (SqlConnection conn = new SqlConnection(cString.c_String))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand("SELECT Product.productID FROM Product " +
"WHERE Product.PLU = '" + helper + "' ", conn))
{
using (SqlDataReader rdr = cmd.ExecuteReader())
{
if (rdr.HasRows)
{
// if code still exist in database, regenerate it
regenerateCode(helper);
}
else
{
//else return code
return helper;
}
}
}
}
return helper;
}
Actually it works fine with example:
1000 (exist)
1001 (exist)
1002 (not exist, insert), but
when code = 1002, it goes into line with else {return helper;} and have no idea why going again to regenerateCode() method..
Any ideas?
It happens because you do nothing with the return value. You pass helper to the recursion, but do not place the return value anywhere. your method should look like this:
string regenerateCode(string toParse)
{
string helper = "";
int parseCode = int.Parse(toParse);
helper = new string('0', 4 - parseCode.ToString().Length);
helper += parseCode + 1;
using (SqlConnection conn = new SqlConnection(cString.c_String))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand("SELECT Product.productID FROM Product " +
"WHERE Product.PLU = '" + helper + "' ", conn))
{
using (SqlDataReader rdr = cmd.ExecuteReader())
{
// Return the next code that doesn't exist
return rdr.HasRows ? regenerateCode(helper) : helper;
}
}
}
}
Also, remember that while string are reference types, they are immutable. which means that a string that is passed as an argument would not change like a normal array. see: How are strings passed in .NET?

datagrid cellvaluechanged event handler for dynamic object

I am programmatically creating a datagrid and I want to take the value of a cell which has been changed from the user, in order to add it to another datagrid.
My code is this:
connTo.Open();
SqlDataReader sqlFromReader1 = null;
SqlDataReader sqlFromReader2 = null;
SqlDataReader sqlFromReader3 = null;
SqlCommand myFromCommand1 = new SqlCommand("select distinct m.catid1, c.descr "+
"from material m "+
"inner join cat1 c on c.id = m.catid1", connTo);
sqlFromReader1 = myFromCommand1.ExecuteReader();
DataTable dt1 = new DataTable();
dt1.Load(sqlFromReader1);
for (i = 0; i < dt1.Rows.Count; i++)
{
//int c1 = (int)(dt1.Rows[i]["catid1"]);
TabPage tbg = new TabPage(dt1.Rows[i]["descr"].ToString());
tabControl1.Controls.Add(tbg);
TabControl tbi = new TabControl();
tbi.Name = i.ToString() + i.ToString();
SqlCommand myFromCommand2 = new SqlCommand(
"select distinct m.catid2, c.descr " +
"from material m " +
"inner join cat2 c on c.id = m.catid2 "+
"and m.catid1 = " + dt1.Rows[i]["catid1"].ToString(), connTo);
sqlFromReader2 = myFromCommand2.ExecuteReader();
DataTable dt2 = new DataTable();
dt2.Load(sqlFromReader2);
for (int k = 0; k < dt2.Rows.Count; k++)
{
//int c2 = (int)(dt2.Rows[k]["catid2"]);
TabPage tbgi = new TabPage(dt2.Rows[k]["descr"].ToString());
tbi.Controls.Add(tbgi);
tbi.Left = 1;
tbi.Top = 1;
tbi.Width = 880;
tbi.Height = 400;
DataGridView gv = new DataGridView();
gv.Width = 850;
gv.Height = 340;
gv.Left = 10;
gv.Top = 10;
gv.ColumnCount = 4;
gv.Columns[0].Name = "code";
gv.Columns[0].Width = 120;
gv.Columns[0].ReadOnly = true;
gv.Columns[1].Name = "name";
gv.Columns[1].Width = 450;
gv.Columns[1].ReadOnly = true;
gv.Columns[2].Name = "price";
gv.Columns[2].Width = 80;
gv.Columns[2].ReadOnly = true;
gv.Columns[3].Name = "qty";
gv.Columns[3].Width = 120;
SqlCommand myFromCommand3 = new SqlCommand(
"select m.code, m.descr, m.cost1 price " +
"from material m " +
"where m.catid1 = " + dt1.Rows[i]["catid1"].ToString() + " " +
"and m.catid2 = " + dt2.Rows[k]["catid2"].ToString(), connTo);
sqlFromReader3 = myFromCommand3.ExecuteReader();
DataTable dt3 = new DataTable();
dt3.Load(sqlFromReader3);
for (int l = 0; l < dt3.Rows.Count; l++)
{
gv.Rows.Add(dt3.Rows[l]["code"].ToString(), dt3.Rows[l]["descr"].ToString(), dt3.Rows[l]["price"].ToString(), "");
}
tbgi.Controls.Add(gv);
}
tbg.Controls.Add(tbi);
Now I want to catch when the user changes the value of gv.Columns[3].Name ("qty") to add this value and the rest of the row data to a new datalist.
How can this been done? Is this possible?
The CellValueChanged event should work in this case.
When you create each new DataGridView instance and add it to a tab just add an event handler:
dataGridView1.CellValueChanged += new DataGridViewCellEventHandler(dataGridView1_CellValueChanged);
Then you have the method dataGridView1_CellValueChanged in single place which is used by all the event handlers.
The signature of the CellValueChanged event handler takes DataGridViewCellEventArgs which has a property for both the column and row index that changed. So you have code like this:
void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 3)
{
// Now you can cast sender to a DataGridView and copy the row at e.RowIndex
DataGridView dgv = sender as DataGridView;
if (dgv == null)
return;
// Here you get the cell value
var cellValue = dgv.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString();
}
}
I'd also recommend assigning dt3 as a datasource. If you do use a datasource rather than an unbound grid the copying of the row will be a lot cleaner.

Passing the value to crystal report

I'm having a hard time to figure out how can i view or seen the values from Visual Studio 2010 C# to Crystal Report.. This is I want to be viewed my report in Crystal Report
As of ????(4:30PM): ????(December), ????(2011)
Juan Dela Cruz
Count: 10
Score: 5
Grade: ????(50.00)
The code below is my button SEARCH to find out the summary of this particular employee.
try
{
econ = new SqlConnection();
econ.ConnectionString = emp_con;
econ.Open();
float iGrade = 0;
float Grade = 0.00F;
string Log_User;
float Count, Score;
string date = DateTime.Now.ToShortTimeString();
ecmd = new SqlCommand("SELECT Log_User, Count = COUNT(Det_Score), Score = SUM(Det_Score) FROM MEMBER M,DETAILS D WHERE D.Emp_Id = M.Emp_Id AND Log_User like" + "'" + Convert.ToString(comEmployee.Text) + "'AND Month(Sched_Start) =" + "'" + Convert.ToInt32(iMonth) + "'AND Year(Sched_Start) =" + "'" + Convert.ToInt32(txtYear.Text) + "'GROUP BY Log_User", econ);
ecmd.CommandType = CommandType.Text;
ecmd.Connection = econ;
dr = ecmd.ExecuteReader();
while (dr.Read())
{
if (dr == null || !dr.HasRows)
{
MessageBox.Show("No record found.", "Error");
}
else
{
Log_User = (string)dr["Log_User"];
Count = (dr["Count"] as int?) ?? 0;
Score = (dr["Score"] as int?) ?? 0;
try
{
iGrade = Score / Count;
Grade = iGrade * 100;
}
catch (DivideByZeroException)
{
Console.WriteLine("Exception occured");
}
}
}
econ.Close();
The code below is my Crystal Report in getting the values from my database: these are included: Log_User, Month and the Year..
ParameterFields myParams = new ParameterFields();
ParameterField name = new ParameterField();
ParameterDiscreteValue valName = new ParameterDiscreteValue();
name.ParameterFieldName = "#Log_User";
valName.Value = comEmployee.Text;
name.CurrentValues.Add(valName);
myParams.Add(name);
ParameterField month = new ParameterField();
ParameterDiscreteValue valMonth = new ParameterDiscreteValue();
month.ParameterFieldName = "#Month";
valMonth.Value = Convert.ToInt32(iMonth);
month.CurrentValues.Add(valMonth);
myParams.Add(month);
ParameterField year = new ParameterField();
ParameterDiscreteValue valYear = new ParameterDiscreteValue();
year.ParameterFieldName = "#Year";
valYear.Value = Convert.ToInt32(txtYear.Text);
year.CurrentValues.Add(valYear);
myParams.Add(year);
crystalReportViewer1.ParameterFieldInfo = myParams;
crystalReportViewer1.ReportSource = CrystalReport81;
}
catch (Exception x)
{
MessageBox.Show(x.GetBaseException().ToString(), "Connection Status", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
All i want is to view my input parameters in the report and also the grade.. (all the values that have ????)
I know there is someone there can help me to figure it out. After this, I've done in my project.
TextObject yr = (TextObject)CrystalReport81.ReportDefinition.Sections["Section3"].ReportObjects["Text1"];
yr.Text = txtYear.Text;
FORM Textbox --> CRYSTAL REPORT Textbox
By adding the code above will enable you to show the value you entered in the textboxes.. but first you should have an empty Textbox in your Crystal Report because that will catch the value you throw from your FORM Textbox
I hope it can help others.. as it helped me a lot..

Resources