I read an excel file and put it in a Datatable.
If I put a breakpoint and inspect the value of myDatatable.Rows.Count() it is equal to the number of rows in my excel file.
But then I pass my datatable object to a method like this:
private void Foo(Datatable dt)
{
DataTableReader reader = dt.CreateDataReader();
while(reader.Read())
{
// do stuff on each row
}
}
Now if I put a counter inside my while loop, it shows for example 10 while the number of rows are really 100000.
What is it I am doing wrong?
That should work similar to a for-each loop on DataTable.Rows
I am guessing somewhere in your while loop you are exiting out of the loop. Make sure you have used "break" and "continue" correctly.
What makes you think anything's wrong? The table will have e.g. 100000 rows, that won't change. The DataReader, iterating over the table one row at a time, will have a different position on each iteration.
Related
I have an application that reads an entire Excel file into a datatable. I need to retrieve subsets of data from this table into separate datatables. I do this by looping down the cells of the Excel table until I find a blank cell.
The problem is that the last line of the longest column of the Excel table (in other words, the last row of the Excel table) always errors out, with "There is no row at position " followed by whatever the last row of the longest column is.
Here is a scaled-down version of my code that gives me the error:
do {
string MyString = dtExcel.Rows[i][11].ToString();
} while (dt.Rows[i][11].ToString().Length > 0);
Where i is the row counter and [11] is the column I need to save. It works perfectly until the last row of the longest column, and then bombs out.
I've tried checking to see if dtExcel.Rows[i][11] is null, or if the ToString() length is zero, but I can't figure out how to trap this error because the mere act of trying to read it causes the error.
I guess my question is, is there a way of checking to see if this row even exists before I try to check it for null or turn it into a string, or whatever?
Hopefully this is clear. Thanks for any help.
Instead of using a while loop checking if the row is empty, use
for(int i=0;i < dt.Rows.Count ;i++){
//...
}
to loop through the rows.
By doing that, it'll know when to stop in advance, and you will not get an
Index out of Bounds Exception
Try reading your datatable this way:
StringBuilder sb = new StringBuilder();
foreach( var r in dt.AsEnumerable())
{
if(string.IsNullOrEmpty(r[11])) break;
sb.Append(r[11]);
}
return sb.ToString();
When I retrieve data into my DataSet, the year column is the 3rd column in my DataSet. I do not need this column after using it do so some calculations, so I remove it using the Remove method passing the column's name to the Remove method. The problem is that I retrieve the data in a foreach loop, so when I retrieve the data again, the year column is now the last column in the DataSet and when I try to access it, it throws an error saying year column was not found. My way around this was to clone by DataSet into a DataTable and then to import each row from the dataset into my DataTable, but is there a more efficient way or a way to keep the year column in it's original position.
private int GetData()
{
dataSet.GetExportData();
DataTable dt = dataSet.ExportData;
for(int i = 0; i <dataSet.ExportData; i++)
{
//Do Stuff
}
dataSet.Columns.Remove(dataSet.ExportData.YearColumn.ColumnName);
}
In the above code, when I open up a dialog and select data to export, it works the first time, but if I leave the dialog open and click the button to export again, it throws the error. If I close the dialog and reopen, it works fine. As I said before I noticed when it retrieves the data again on the button click with dataSet.GetExportData(), it puts the Year column as the last column instead of the defined position in the strongly-typed DataSet which I assume is the problem, but can't figure out how to fix it besides doing a Clone and Import.
It'd be better to be in comment, but I want to take advantage of code styling, also it's hard to say what exactly you want to achieve without sighting the code,
foreach (DataRow row in myTable.Rows)
{
//do something with year column
myTable.Columns.Remove("year");
}
above code works fine in the first iteration, but will fail afterwards, as myTable.Columns.Remove("year") removes the whole column, from the table not just from current row, and gives you: You'll get Column 'year' does not belong to table Table.exception.
Why not taking myTable.Columns.Remove("year"); out of the foreach instead?
foreach (DataRow row in myTable.Rows)
{
//do something with year column
}
myTable.Columns.Remove("year");
Am using foreach loop that contain some code to retraive data from database. first time it returns some rows from database.In second looping it returns some rows so and so. My question is may i merge the looping rows to single dataset?.
please help me to merge that row values to single dataset....
As #Tim Schmelter mentioned there is also the Merge() method on datasets. This will allow you to different types of merges, including updates which will stop you having duplicate rows if you have the same row in each dataset. This maybe better than using a for loop to add the rows from one to the other depending on the type of data you have.
you can read more on this here:
http://msdn.microsoft.com/en-us/library/803bh6bc.aspx
This is provided I understood you correctly ...
DataTable tbl = new DataTable();
foreach (DataRow row in data.Rows)
{
tbl.Rows.Add(row);
}
Then just add the DataTable to a DataSet of your choice.
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?