ADO, DataGrids and writing to file

FuturShoc

Active member
Joined
Jul 28, 2006
Messages
27
Location
Hot Springs, Arkansas
Programming Experience
3-5
I'm still very new to .NET development but have a background in MySQL, PHP and other scripting.

I need to work with SQL tables, displaying those results in a datagrid and writing those results out to a file.

My real question. I need some kind of concise (*gasp!*) instruction on working with datasets, SQL tables and datagrids in .NET. Can someone point me to some good, solid tutorials? I just do not understand the hows and whys of how they relate to eachother and interact. I've googled this alot, but so much of the material I come up with makes far, far too many assumptions about what I already know. I've even tried the MS virtual labs on ADO.NET, but they say alot without telling me *anything*.

For example, I need to fetch rows from a SQL table, display them in a datagrid and likely save that result set to a file. Then I need to iterate through each of those rows in the datagrid and act on the data in those rows in some way. * Where do I go to for this data? The dataset? The datagrid? I have no idea where to start for either approach.

-- Extremely frustrated and just about ready to smash it all with a baseball bat.
 
For now, forget datasets. Concentrate on Datatables, in a Datatable is a collection of datarow objects, and datacolumn objects (fields) You can bind nearly any control to datacolumns in the datatable, or you can display all data in the datatable in a datagridview. When you manipulate data in any bound control changes are reflected in the datatable.

Now i'm going to stop rambling on and say...

Do a member search for a chap called TechGnome on these forums. In his signature you will find 2 very good tutorials - Intro to ADO.Net part I and II.
Check them out.
 
Bah.. where's my big-up, with my signature, with even better tutorials written by microsoft? ;) FuturShoc - have a read of DW2.. and dont shy away from datasets too much! DataSets are after all, just a collection of datatables - vis is right in that datatables are the useful parts and should be focused on, but dont forget to learn what a dataset is and what its used for (it takes about 5 minutes to appreciate a dataset once you know about datatables)
 
By the way FuturShoc there's also another superb tutorial in another members signature. Search for Cjard and check out the DW2 tutorial in his signature.:)
 
Ok, these tutorials are helping, yes.
However, there is still one big gap here for me.

Doesn't anyone ever act upon the data in a table to use that data externally?

Just as an arbitrary example, I get some computer names from a datatable. Then, I want to grab all of them and write them out to a file. I have YET to see any instruction on how to get the data OUT OF the table for use elsewhere in my code.

In PHP, I take the result data from my query and just loop through the array and echo out the data I want on each row...

echo $Row['computer_name'];

This gets me the string "myfancycomputer" because thats the value of the "computer_name" column of that row of the table.

Why does it seem to be some kind of guarded secret in .NET? I just don't get why it has to be so hard. I've been futzing with intellisense in .NET for days and can't get even this simplest return.

Here's the existing code I'm using. At this point, the code gets query results and fills a datagrid. All that works. But I need to ACT ON some of the strings in these rows. Plain and simple, you would think. But its beyond me at this point.

mySqlConnection.Open()
'***Assign the connection property
mySqlCommand.Connection = mySqlConnection
DataGrid1.DataSource = Jobs.Tables("tblDownloaded_Jobs")
mySqlCommand.CommandTimeout = 2
Dim reportSQLCommand As String = "select distinct(userid), count(distinct job_name) job_total from tbldownloaded_jobs where userid in (select distinct(userid) from tbldownloaded_jobs) AND date_created > '" & fromDate_string & "' AND date_created < '" & toDate_string & "' GROUP BY userid"
mySqlDataAdapter = New SqlDataAdapter(reportSQLCommand, mySqlConnection)
mySqlDataAdapter.Fill(myDataSet, "tblDownloaded_Jobs")
txtRecords.Text = Me.Jobs.Tables(0).Rows.Count.ToString
 
Last edited:
That's the rub though.... it depends on what you want to do with it.... Once you have it in a DS/DT.... you can access it almost as easily as an array:

myDataTable.Rows(0).Item(0).ToString is the first field of the first row....
You can also Loop For Each myDataRow as DataRow In myDataTable.Rows and get the info that way.... there's a number of ways you can do it, it's all about WHAT you want to do with it.

-tg
 
Aha.
I did a bit of digging in other threads and looked at some other poster's code to see if I could pick out the specific chunk I'm missing. I think I've got something, but I'd like to know if this approach is wonky or not exactly a "best practice".

VB.NET:
Dim myRow As DataRow
For Each myRow In myDataSet.tblDownloaded_Jobs.Rows
    MsgBox(myRow("userid"))
Next
The key here for me is now knowing that myDataSet.tblDownloaded_Jobs.Rows is a collection of the rows... Now that I know that, it was extremely helpful in showing me where to go next to then extract the values in those rows...

I'm just stumped as to why this simple fact isn't mentioned in anything I've read so far. Its as though I had to know the Secret ADO.NET Club Handshake to get that question answered. :mad: By that I mean, answered by .NET in general. No jab at you guys.

But I'm sure a slightly happier guy to know it now. :eek:
 
Last edited:
That's the rub though.... it depends on what you want to do with it.... Once you have it in a DS/DT.... you can access it almost as easily as an array:

myDataTable.Rows(0).Item(0).ToString is the first field of the first row....
You can also Loop For Each myDataRow as DataRow In myDataTable.Rows and get the info that way.... there's a number of ways you can do it, it's all about WHAT you want to do with it.

-tg

Many thanks for your response, TG. I very much appreciate your follow up to the thread. I'll incorporate your example in my testing to help further familiarize me with how this works.
 
the way you mentioned and the one I metioned are both perfectly accepted. Neither is "wonky" ... as I stated, it truly is up to your needs as to how you interact with it.

-tg
 
Its not answered because *typically* we dont use datatables in this way

DataTables as a client-side in-memory repository of data (that may or may not be all, some or none of what is in a database table) are typically used for components - the contents are shown in textboxes, grids and combos. They may be updated by the user and then sent back to the database.

We dont often do operations on each row

I do want to point out at this juncture, that for the purposes of writing out to a file, a datareader is much more suitable than a datatable. Actually, a table adapter uses a datareader to pull data out of the database and put it in the table. In this regard, the datatable is something of a middleman and it eats your memory.. you might not care if the number of records is low, but if you are writing 700 megs of data to a file, then using a datatable would need 700 megs of ram to store all the data as an interim

Using a datareader in this scenario would mean that the data can be dripped from the database into the file for a low memory overhead.

An analogy could be watering your garden, needing 10 gallons of water. If you bought a 10 gallon watering can (datatable) and filled it, youd have a very heavy (memory consuming) thing to carry while you water the garden(write the file)
If you had a hose (datareader -> file writer) that could spray far enough to water everything, then your job of carrying the hose would be a much lighter one


So how do we get a datareader? Well, you can go the long way of setting it up, or you can get a little help from your table adapter which is already set up. Typically, because it is only designed to read and write datatables it doesnt expose the reader it uses to do this. Youll need to expose it yourself by adding a little bit of code into the back end.
Right click the tableadapter in the dataset and choose View Code
It actually puts you into viewing code for the DataTable, which isnt what we want.
We will have to modify the namespace that we are in (all tableadapters go in their own tablespace) and add a partial class

In my project called Credaro, i have a dataset called CredaroDS. It is thus the rule that the tableadapters namespace is called Credaro.CredaroDSTableAdapters

the following code:
VB.NET:
Imports System.Data.OracleClient

Namespace Credaro.CredaroDSTableAdapters
  Partial Class [B]CRDO_CREDIT_EVALUATIONTableAdapter[/B]
    Public Function GetReader() As OracleDataReader 
      Me.Adapter.SelectCommand = Me.CommandCollection(0);
      Return Me.Adapter.SelectCommand.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
    End Function
  End Class
End Namespace
This partial class MUST have the same name as your tableadapter (bold) - it is not an extension of the class, more like an addition - the two partials will be combined to make a single suring compilation. Because the other part of the class is generated by the IDE, it is destroyed and regenerated every time a change is made in the visual designer. this is why we dont put our code in with the stuff that will be destroyed.

Now we can (hopefully) get a reader that emits fields with the same signature as the datatable

-

I want to talk, at this point, about stong versus weak typing.

When you put a dataset into your project, and name all the tables, it makes a Strongly Typed dataset. This dataset descends from the generic DataSet, which is weakly typed. If you dont know about inheritance in object oriented languages, go learn it now.

All the datatables within your strongly typed dataset (lets call it STDataSet) are also strongly typed, and all the rows in those tables are strongly typed too


Often I see this code:
VB.NET:
For Each ro as DataRow in STDataSet.Tables("STDataTable").Rows
 If DirectCast(ro.Item("STDataColumnInt"), Integer) = 0 Then ...

and i'm like "No, no, nooo..."
There is no point setting up a strongly typed set and then using it in weakly typed mode, and having to cast everything every time you want to use it!

We write this:
VB.NET:
For Each ro as [B]STDataRow[/B] in [B]STDataSet.STDataTable[/B].Rows
 If ro.STDataColumnInt = 0 Then ...
It means intellisense can help us write it, we get the types right, we dont have to remember what every single column is called and there is no ugly, messy, lengthy casting (cause vb's syntax for casting is awful compared to c#) just to remove the "object flavoured wrapping paper" from our "integer" value

So.. Bear it in mind. If you have a typed dataset, always work with it in typed mode as much as possible! If you are ever specifying a table name, or column name as a string, or integer:
MyTypedDataSet.Tables("SpecifyingTableNameAsString")
MyTypedDataSet.Tables(0)

MyTypedDataSet.Tables(0).Columns("SpecifyingColumnNameAsString")
MyTypedDataSet.Tables(0).Columns(0)

Think to yourself, "no - i'll see if I can do it the easier, better, safer, faster, typed way":
MyTypedDataSet.SpecifyingTableNameDirectly

MyTypedDataSet.SpecifyingTableNameDirectly.SpecifyingTableNameDirectlyDATACOLUMN



Exceptions to this are when you really need to use a for loop with an Integer indexer, but try to use a for/each in this case if possible..


-

Lsat point of note, now you know this..


DataReader is never subclassed by the IDE. There is no STDataReader for the STDataTable, so your little hack above has to simply return a generic datareader.. and this HAS to be used like this:

VB.NET:
While reader.Read() 'advances the reader to the next line

  fileWriter.Write(reader.GetString(2)) 'get the third column as a string
  fileWriter.Write(reader.GetInt32(7)) 'get the 8th column as an int
or like this:
VB.NET:
While reader.Read() 'advances the reader to the next line

  fileWriter.Write(reader("PersonName")) 
  fileWriter.Write(reader("PersonAge"))


you cannot use the generic datareader like:

VB.NET:
While reader.Read() 'advances the reader to the next line

  fileWriter.Write(reader.PersonName) 
  fileWriter.Write(reader.PersonAge)
 
Back
Top