Why can't DataTable.Load(IDataReader) load one row? - c#

I am using DataTable.Load(IDataReader) to load data from db.
When I load one record, DataTable.Rows.Count shows a count of 0, but when I load more than record DataTable.Rows.Count shows the right Count.
Does this mean DataTable.Load Method takes two rows and above?
This article was helpful but didn't answer my question
https://msdn.microsoft.com/en-us/library/system.data.datatable.load(v=vs.110).aspx.
Code
DataTable dt= new Datable
IDataReader rsg = DataClass.GetDBResults("sp_GetNames", "#Names", names);
if (rsg.Read())
{
dt.Load(rsg);
int num = dt.Rows.Count;
//More Code
}
num is 0 if the procedure,sp_GetNames returns one record.

You're calling Read(), which reads the first record, and then you're calling Load(). The problem is that, after calling Read(), the pointer to the "current record" in rsg has already moved past the first record and is pointing to the next record (if there is one). The call to Load() is only going to read the rest of the records, since IDataReader is a forward-only mechanism.
Call Load() without the first call to Read().

Related

Unable to check for changed rows in a dataset

I have a table within my program which stores information about messages and would like to detect when new information has been added to it. The reason I am doing this is beucause I would like to show the new data to the user only when there is new data instead of having to constantly get all the rows and display them.
The way I decided to do this was through the use of the dataSet.HasChanged() function which should essentially check the dataset for any new rows and a function called DataChanged returns dataSet.HasChanged() value.
However, the function I am using always returns false (even when there are changes)
Here is the function...
public bool DataChanged(string Table)
{
//This is the variable that will be returned
bool ChangesMade;
//Create the adapter
OleDbDataAdapter adapter = new OleDbDataAdapter(Table, connector);
//Clear the current data in the dataset
dataSet.Clear();
//Open the connection and fill the dataset
connector.Open();
adapter.Fill(dataSet, "TableData1");
connector.Close();
return ChangesMade = dataSet.HasChanges();
}
Changes for some reason are never detected and therefore this function always returns false even after I add a new record to the dataset.
An alternative method that provides the functionality explained in paragraph one would be very helpful and the fixing of my current method ever more so.
Here is an easy way to do this.
Make sure a Timestamp/Rowversion column exists for each table you wish to track changes to.
Return the current database Timestamp to your calling program as part of your data result set (DataSet in this case). For example, add the following query to your result set.
SELECT ##DBTS;
Use this returned value the next time you run your query with the following added to the existing WHERE clause(s) as appropriate.
...
AND (#LastRowversionValue IS NULL
OR TableName.RowversionColumn > #LastRowversionValue)
...
Pass NULL for the #LastRowversionValue the first time the query is ran to get the process started.
Any rows that are inserted/updated into the table(s) since the last time you retrieved data, will have an Rowversion greater than the one you stored from the last execution.

Is using reader from CreateDataReader different from looping on Datatable.Rows

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.

Insert a DataRow inside a table

I have a function that returns a typed DataRow object and now I would insert this DataRow in a given table. As far as I know I could do this using TableAdapter in two ways: TableAdapter.Update and TableAdapter.Insert.
Both ways seems pretty simple to use but, first way could even delete row from the table (essentially my DataSet will be "serialized" on my DB table) and since this table is really the application's critical part I would avoid any chance of data deletion, so I would prefear Insert method.
The problem seems to be that Insert method doesn't accept a DataRow object as it's parameter (unlike Update), so I need to manually insert each parameters. Alas I have at least 80 parameters so this is a really really headache operation. What can I do now?
The update method does allow you to insert,update or delete changes in the tableAdapter. MSDN: 'Use the TableAdapter.Update method when your application uses datasets to store data. The Update method sends all changes (updates, inserts, and deletes) to the database'. Although Insert is ment for usage if you want more control for you data inserts but does not allow you to pass a datarow instead Parameters must be used. See complete reference on MSDN: http://msdn.microsoft.com/en-us/library/ms233812(v=vs.110).aspx
Code example of Update method usage.
// Create a new row.
NorthwindDataSet.RegionRow newRegionRow;
newRegionRow = northwindDataSet.Region.NewRegionRow();
newRegionRow.RegionID = 5;
newRegionRow.RegionDescription = "NorthWestern";
// Add the row to the Region table
this.northwindDataSet.Region.Rows.Add(newRegionRow);
// Save the new row to the database
this.regionTableAdapter.Update(this.northwindDataSet.Region);
Code example Insert:
NorthwindDataSetTableAdapters.RegionTableAdapter regionTableAdapter =
new NorthwindDataSetTableAdapters.RegionTableAdapter();
regionTableAdapter.Insert(5, "NorthWestern");

DataReader has rows and data, trying to read from it says "no data is present"

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

How do I Skip the first row in an sqldatareader

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?

Categories

Resources