I am getting this error: Data Could not be read. Data is Null. This method or property cannot be called on Null values.
I know the Database has NULL values in some fields. I just want to handle them and continue filling in the next row. Here's some code:
rdr is the SqlDataReader
if (rdr[EmailID] != null)
{
//this blows up on this line on the 32nd iteration of the loop when searching for an extended group.
EmpNewData.SelectSingleNode("/my:myFields/my:Emp/my:EmpData/my:email", NamespaceManager).SetValue(rdr.GetString(EmailID));
}
else
{
EmpNewData.SelectSingleNode("/my:myFields/my:Emp/my:EmpData/my:email", NamespaceManager).SetValue("No.Email");
}
I could handle this with the Stored Procedure, but I'd really like to know how to handle this. Above is one of many iterations I've tried.
Thanks.
I figured this out. IsDBNull seems to take care of it. I ran thru the code in debug to check where the ordinal sat. It was 14 in this case.
int EmailID = rdr.GetOrdinal("EmailID");
Then when using GetString:
if (!(rdr.IsDBNull(14)))
{
EmpNewData.SelectSingleNode("/my:myFields/my:Emp/my:EmpData/my:email", NamespaceManager).SetValue(rdr.GetString(EmailID));
}
else
{
EmpNewData.SelectSingleNode("/my:myFields/my:Emp/my:EmpData/my:email", NamespaceManager).SetValue("No Email");
}
I hope this will help somebody.
Related
So.... I have created a new project, I have added a database and dataset, created a table, populated it, set it as a data source, and finally have pulled a 'details' and 'datagridview' onto my form.
I have tested these and all displays just fine.
Now the problem. I want to call a cell value and then carry out a task based on the result, but everytime I try, I get an out of range exception.
I've looked around at other topics and tutorials and similar questions and it suggests that I'm trying to call a cell that doesnt exist. This doesnt make sense, as I've tried various low-number index combinations, and my table consists of 4 columns and 16 rows, all of which contain data.
All other indicators point to the program not understanding that the datagridview actually contains data - as if it wants to me to define it before it can call the data - but this makes no sense to me because I've pulled it from a database and I can view the data with no problems when I run the program.
I've tried various different codes to call on a cell, but I get the same exception every time.
int testValue1 = (int)islandMapDataGridView[1, 1].Value;
Console.WriteLine(testValue1);
I should point out that I'm reasonably new to this. What am I doing wrong?
EDIT - Thank you for pointing me to a similar question with a lengthy answer - unfortunately I've looked at many just like this already. They are suggesting that I'm picking a cell that does not exist.
I am aware that these indexes start at 0 and I should compensate for this. Again, my datagridview has 4 columns and 16 rows. I am (for example) attempting to get the data at cell index 1,1 - which is well within the range of the datagridview.
The problem does not seem to be that I am calling a cell that falls outside the range of cells and rows in the datagridview but rather that it seems to think that nothing is there at all. But if I disable the line of code that is supposed to return the value - when I run the program I can see the table just fine and the data is there.
If I have to take the time to define the datagridview just so I can call a value from a cell, then what was the point in setting up databases, datasets, datasources and tables in the first place?
2nd EDIT - What do I have to do to get this looked at again?????
Somebody has stated this is an exact duplicate of another question, and linked me to it. It is NOT an exact duplicate. I am NOT trying to reference a cell that falls outside of the datagridview.
The problem seems to be that the datagridview is not properly reporting back the data contained within in. Presumably I have missed some sort of initialisation, or there is something wrong with the binding.... I dont know... If I knew, then it wouldnt be a problem. The linked topic/question does nothing to explain what I am missing.
Please can I get some help with this?
Please?
3rd Edit - I'd like to add that since my opening question, I've been looking around and trying to find a solution - I stumbled across a tutorial carrying out a similar exericse, and they included the following line of code:
islandMapDataGridView.SelectionMode = DataGridViewSelectionMode.CellSelect;
I hoped this might resolve my problem, but sadly it did not.
I am guessing that something fundamental is missing that allows me to report values from the datagrid, or it is somehow not properly loaded or configured.
I would appreciate any help - even if just to point me a tutorial or similar which expains how to set this sort of thing up.
Do I need to set up a class in order to fetch a value from a cell? Do I need to set up a database context? Please, what am I missing here?
4th Edit! -
Ok so here is the code that was automatically generated by the program when i dragged in the 'datagridview' and 'details' from the table in datasources.
private void islandMapBindingNavigatorSaveItem_Click(object sender, EventArgs e)
{
this.Validate();
this.islandMapBindingSource.EndEdit();
this.tableAdapterManager.UpdateAll(this.starterIslandDataSet);
}
private void Form4_Load(object sender, EventArgs e)
{
// TODO: This line of code loads data into the 'starterIslandDataSet.IslandMap' table. You can move, or remove it, as needed.
this.islandMapTableAdapter.Fill(this.starterIslandDataSet.IslandMap);
}
There doesnt appear to be anything specifically here for the datagridview - but again, when i run the program, it displays it just fine, including all the information that i entered into the table.
Here is the code I am trying to use to pull info from the database -
private void MapTilesTest()
{
islandMapDataGridView.SelectionMode = DataGridViewSelectionMode.CellSelect;
foreach (Control control in tableLayoutPanel2.Controls)
{
PictureBox maptile = control as PictureBox;
if (maptile != null)
{
int testValue1 = (int)islandMapDataGridView[1, 1].Value;
Console.WriteLine(testValue1);
}
}
I am using console.writeline just to confirm that i can indeed pull a value from the table.
I have looked at tutorials for advice, and i see lots where they are manually coding the datagridview and manually inputting the data into the datagridview in the code - i assume this is one way of doing it - but i cant find a good example where someone is pulling information from a database in the same way.
After reading the comments, it may be helpful to clarify some major points in what you are trying to accomplish. First is the reality that when you try to access a cell’s value in a grid, it is imperative that you check several possibilities.
First, does the cell actually exist? In your posted example, you are trying to access the value from the cell at row 1 column 1. This can be accomplished by simply checking to make sure the grid has at least two (2) rows and at least two (2) columns. If you do not check this, and the grid has less than two (2) rows or less than two (2) columns… your code will crash and burn. This obviously is a bad thing and “you” as a programmer should ALWAYS assume the possibility that the cell you are looking for does not exist, is null or the cells value is not a number.
If you have not done so yet, I recommend you take a look at the Try/Catch construct. This useful construct will allow you to TRY some part of your code and CATCH any errors… like an index out of range error. The try catch construct is useful to catch errors and respond to them. In your posted code there would be three possible errors in the line int testValue1 = (int)islandMapDataGridView[1, 1].Value; And you would want to catch all these possible errors in the following order.
1) The cell at row 1 column 1 does not exist.
2) The cells “Value” at column 1 row 1 is null.
3) The cells “Value” at column 1 row 1 is not a number.
The line int testValue1 = (int)islandMapDataGridView[1, 1].Value; could produce one of the three errors above. If the cell does not exist, is null or is not a number, then there would be no value to output.
The convenient aspect of the Try/Catch is that you can “catch” all errors or specific errors. Example, the code below will catch all three possible errors.
private void MapTilesTest() {
try {
int testValue1 = (int)islandMapDataGridView[1, 1].Value;
MessageBox.Show("Value is: " + testValue1.ToString());
}
catch (ArgumentOutOfRangeException ex) {
MessageBox.Show("Cell 1,1 does not exist: total rows = " + islandMapDataGridView.Rows.Count + " total colums = " + islandMapDataGridView.Columns.Count);
}
catch (NullReferenceException ex) {
MessageBox.Show("The 'Value' at Cell 1,1 is null (most likely the new row): total rows = " + islandMapDataGridView.Rows.Count + " total colums = " + islandMapDataGridView.Columns.Count);
}
catch (InvalidCastException ex) {
MessageBox.Show("The 'Value' at Cell 1,1 is NOT a number or is an empty cell: actual cell value is: " + islandMapDataGridView[1, 1].Value.ToString());
}
catch (Exception ex) {
MessageBox.Show("Some other error: " + ex.GetBaseException());
}
}
A second approach is to manually check for these errors. The code below demonstrates this and also uses an int.TryParse construct to validate if the value in the cell is actually a number. Using a TryParse is a better way to convert strings to numbers and validate the string is actually a number. Casting a string to an int as your code does, ALWAYS has the possibility of failure and should ALWAYS be checked. The Try/Parse construct helps in this checking.
The code below still uses a Try/Catch however the difference is that the code below is manually checking for the specific errors: index out of range, a null cell value and valid integer string values. These error checks are made BEFORE they happen and therefore the exceptions will not be thrown. If there are ANY other exceptions thrown… the catch clause will get them.
private void MapTilesTest() {
try {
// make sure there are enough rows
if (islandMapDataGridView.Rows.Count < 2) {
MessageBox.Show("Row Index is out of range: total rows = " + islandMapDataGridView.Rows.Count);
return;
}
// make sure ther are enough columns
if (islandMapDataGridView.Columns.Count < 2) {
MessageBox.Show("Column Index is out of range: total columns = " + islandMapDataGridView.Columns.Count);
return;
}
// make sure the cells value is not null
if (islandMapDataGridView[1, 1].Value == null) {
MessageBox.Show("Value is null (most likely the new row)");
return;
}
// Make sure the cells value is actually an integer
int testValue1 = 0;
if (int.TryParse(islandMapDataGridView[1, 1].Value.ToString(), out testValue1)) {
MessageBox.Show("Valid Value is: " + testValue1.ToString());
}
else {
MessageBox.Show("Value is not a number: " + islandMapDataGridView[1, 1].Value.ToString());
}
}
catch (Exception ex) {
MessageBox.Show("Error: " + ex.Message);
}
}
I hope this makes sense. Lastly, I can assure you that the error you are getting is coming from when the data is being filled into the grid. Obviously, when the first row is filled with data, your code will crash without these checks and this is exactly what is happening. When I asked you to show where the line is being called and you responded with it is being called in the method MapTilesTest, does not help. We need to know WHEN is the MapTilesTest method called in relation to when the grid is filled. I can only assume that MapTilesTest is getting called (before or during) when the grid is filled with data and therefore will cause the error you describe as soon as the first row is added to the grid.
The code only checks if condition, it avoids else condition, anything i'm doing wrong while using IsDBNull?. If the "if" condition fails, i want it to go to else condition.
while (rd.Read())
{
if (!rd.IsDBNull(0))
{
//update table
}
else
{
//update table
}
}
Can anyone help me on this thanks
Are you sure your record even has any rows? If not, it might appear as if your if is failing, when in fact, it is never being called.
You can check this using the property HasRows.
An if statement will always go to the else if the condition is false.
I cannot see your table so I can only speculate that for ever row read, the first column (usually a PK) is not null.
Remember, that loop will stop once there are no longer any rows to read. And what you are checking is if the first column is null (which, as you can see, it never is)
The if statement works and has always worked.
I haven't used DataReaders in ages (I prefer to use an ORM) but I'm forced to at work. I pull back the rows, and check that HasRows is true; debugging at this point and examining the reader shows that my data is there.
Now here's the issue: the moment I call reader.Read(), trying to expand the results says "The enumeration yielded no results" or whatever, and I get the "Invalid attempt to read when no data is present." error. I get the same thing if I don't call Read() (which is the default since the DataReader starts before the first record).
I cannot remember the proper way to handle this; the data is there when I check HasRows, but is gone the moment I either try to read from it right after or after I call Read, which makes no sense as if I don't call Read, the reader should still be before the first record, and if the property is set that starts it at the first record (SingleRow? I forget the name of it) is set, then I should be able to read rows without calling Read, however both ways seem to move past the row containing the data.
What am I forgetting? Code is fairly straightforward:
TemplateFile file = null;
using (DbDataReader reader = ExecuteDataReaderProc("GetTemplateByID", idParam))
{
if (reader.HasRows) // reader has data at this point - verified with debugger
{
reader.Read(); // loses data at this point if I call Read()
template = new TemplateFile
{
FileName = Convert.ToString(reader["FileName"]) // whether or not I call
// Read, says no data here
};
}
}
Just to clarify the answer, it was using the debugger since expanding the results view calls Read() and therefore it moves past the row. As Marc Gravell said in a comment: Debugger considered harmful
If you want to put the data into a file, start by loading a DataTable instead of using a DataReader.
With the DataReader, as has been mentioned in the comments, you might want to iterate through the result set with a while loop
while (reader.Read())
{
}
The loop reads one row at a time and quits when all of the rows have been read.
Once you move to the next row, the previous rows are no longer available unless you have put them into some other structure, like a list or DataTable.
But you can use a DataAdapater to fill a DataTable so there might not be a reason to use a DataReader. Then you can write to a file from the DataTable.
In any event, I don't see how this line could work.
FileName = Convert.ToString(reader["FileName"])
I can post additional code for either approach if you like.
HTH Harvey Sather
I am retrieving 10 rown from my database but I want to skip the first one. Reason being that the first item in my table is already displayed within the main div on my page. Now I want to list all the other remaining records underneath it. How do I accomplish this?
My code works ok and I can display all records from the reader. All I need now is how to skip the first one.
Just read the first one, then continue with the others:
myReader.Read();
while(myReader.Read())
{
//do stuff
}
If you like to use Linq, here's a trick to make it work with DataReaders, using a simple extension method :
public static IEnumerable<IDataRecord> AsEnumerable(this IDataReader reader)
{
while (reader.Read())
{
yield return reader;
}
}
You can then use the Linq Skip method :
using (var reader = command.ExecuteRead())
{
foreach(var row in reader.AsEnumerable.Skip(1))
{
// whatever you do with the data...
}
}
Just call reader.Read() one extra time to start with, to advance to the next record. Then treat the reader as normal. You may want to still check the value of reader.Read() from that first call - if it returns false then there wasn't even the first record you were expecting.
I can't help thinking that there's got to be something else "wrong" when you require skipping the first row in your DataReader like:
Maybe your SQL query, sproc or whatever should exclude the first row instead?
Why do you already have your first row? Maybe you could get all the rows at the same time?
Your question implies a lack of coding experience - either in general or with regards to DataReader or something. Maybe you could get even more help if you explained why you need to skip the first row?
The following post relates to the System.Data.SQLite data provider by phxsoftware (http://sqlite.phxsoftware.com)
I have a question (and possibly a problem) with DbDataReader’s Read method and/or Visual Studio 2008. In many examples I see things like the following (and I know this code doesn't make a lot of sense ... but it serves a purpose):
DbDataReader reader = null;
Long ltemp = 0;
lock (m_ClassLock)
{
DbCommand cmd = dbCnn.CreateCommand();
cmd.CommandText = “SELECT col1 FROM table1”;
reader = cmd.ExecuteReader();
if (null != reader)
{
while (reader.Read())
{
ltemp += (long)reader[0];
}
}
reader.Close();
First question - What I dont understand from this example is am I missing data the first time through the while loop by calling reader.Read() upfront? For instance, if the reader has values (3,5,7,9) the returned reader from cmd.ExecuteReader() should be pointing at 3 initially, correct? reader.Read() would then move to 5, 7, and 9 on subsequent invocations within the while loop. But, because reader.Read() is invoked before the first "ltemp += ..." line am I skipping past the first result (3)?
Second question - (and I'm starting to think this might be a bug in VS) If I step through this set of code in the debugger when I stop at a breakpoint on the "if (null != ..." line I can clearly see mu mousing over and drilling down in the popup that reader has multiple row data values assigned to it. However, if I close that popup information, and then try to bring it back up, when I drill down I now see the line "Enumeration yielded no results" where there was clearly data before.
Can anyone explain this behavior?
Think about it like this after you run ExecuteReader the set is on row -1. You need to execute Read to get to row 0.
IDataReader is a forward only structure, you can only iterate through it once, the debugger is iterating through it.
General questions:
Why the lock?
Why the null check for reader - I am not aware of any issues where ExecuteReader return null after a select.
Why not "SELECT SUM(col1) from table1
Why are you not following the dispose pattern?