After the DataReader has been executed, the results of the query are available using the Read method of the DataReader. Each time the Read method is called, a new row of the query results are provided. To transfer all of the results into our arrays, the Read method is called until it returns False. Perfect for a Do-While loop.
One of the advantages of the .NET Foundation is the wealth of built in functions available in the objects. For example, since we're going for efficiency in this example, we will use the BeginUpdate and EndUpdate methods of the ListBox control. These methods allow the ListBox to be conveniently updated without being repainted on the screen each time a change is made.
ADO.NET features another performance option. Let's look at just the artDate field of the database to see how it works. In the old ADO, you would probably access the actual columns in the old ADO RecordSet (RecordSet isn't in ADO.NET) with a statement similar to this new ADO.NET statement where the column is referenced by name.
~~~~~~~~~~~~~~~~~~~~~~~~~
dteAboutVBDate(I) = odtrAboutVBDataReader.Item("artDate")
~~~~~~~~~~~~~~~~~~~~~~~~~
DataReader provides a series of methods to access column values in their native data types (GetDateTime, GetDouble, GetGuid, GetInt32, and so on). These typed accessor methods perform better by returning a value as a specific .NET Framework type and don't require additional type conversion. (If you want to see the whole list, Microsoft provides it here.)

