How to store database resultset? - vb.net

I want to know which is the best way to store database value in vb.net, For example, I've this code:
Dim conn As MySqlConnection = Connection() 'Return a connection obj
conn.Open()
Dim transaction = conn.BeginTransaction
Dim cmd = New MySqlCommand("SELECT * FROM tb ORDER BY ID")
Dim ResultSet = Cmd.ExecuteReader
If ResultSet.HasRows Then
Do While ResultSet.Read
'Here the value should be store
Loop
End if
How you can see I take all table from my database, now I want store each records in a structure that allow me to access it like the table. An array is good for do this? A list? Which is the best way?

There is no best way. You have different options. For example:
As an option you can use a DataTable
Also you can store values in a generic List(Of T).
If you prefer working with DataTable it will be more simple to use DataAdapter to fill the DataTable. This way you can also create your List(Of T) from your DataTable.
Example of Using DataDapter to fill DataTable
Dim Connection = "Connection String"
Dim Command = "SELECT * FROM Category"
Dim Adapter = New SqlDataAdapter(Command, Connection)
Dim Table = New DataTable()
Adapter.Fill(Table)
This way the DataTable will have columns with name of columns in your result set.
Also you can fill your data in a List(Of T) using the DataTable this way:
Dim ListOfCategory = Table.Rows.Cast(Of DataRow) _
.Select(Function(Row)
Return New Category With
{
.Id = Row.Field(Of Integer)("Id"),
.Name = Row.Field(Of String)("Name")
}
End Function).ToList()
Note
If can change the way you are writing your application, you can use Entity Framework as a good option to work with data.

Related

Test for empty cell Access DB VB.net?

I'm wondering on whether its possible to check if a specific cell in a record is empty before attempting to collect its value and crashing the program if it cant be assigned to a variable.
Something along the lines of SELECT FirstNameColumn FROM tableNames WHERE LastNameColumn = "Smith", and to test if the FirstNameColumn has a value in it.
Im using VB.net, with the OleDB and an Access Database.
If you had some code that retrieved a record, and some of the values on the row might be null:
Public Sub ReadMyData(ByVal connectionString As String)
Dim queryString As String = "SELECT FirstNameColumn FROM tableNames WHERE LastNameColumn = 'Smith'"
Using connection As New OleDbConnection(connectionString)
Dim command As New OleDbCommand(queryString, connection)
connection.Open()
Dim reader As OleDbDataReader = command.ExecuteReader()
While reader.Read()
If Not reader.IsDbNull(0) Then
Console.WriteLine(reader.GetString(0))
End If
End While
reader.Close()
End Using
End Sub
A DataReader has an IsDBNull method hat will tell you whether a cell on a row is null.
Really though, using a DataReader is really low level and quite hard work. There are a lot easier ways to use a database. The next step up might reasonably be a dataadapter and datatable, offering a similar function:
Dim da as New OleDbDataAdapter("SELECT FirstNameColumn FROM tableNames WHERE LastNameColumn = 'Smith'", connStr)
DataTable dt = new DataTable()
custDA.Fill(dt)
For Each ro as DataRow in dt.Rows
If Not ro.IsNull("FirstNameColumn") Then
Console.WriteLine(ro("FirstNameColumn"))
End If
Next ro
TableAdapters another level of abstraction, removes all the horrible dealing with string column names amongst other things:
Dim ta as New PersonTableAdapter
Dim dt as PersonDataTable = ta.GetData()
For Each ro in dt
If Not ro.IsFirstNameColumnNull() Then
Console.WriteLine(ro.FirstNameColumn)
End If
Next ro
Entity Framework is probably equivalently high level, possibly higher:
Dim p as Person = context.Person.Where(Function(x) x.LastName = "Smith")
If p.FirstNameColumn Is Not Nothing Then
Console.WriteLine(p.FirstNameColumn)
End If

vb.net Loading Images from Access Database to DataTable?

So I have a MS Access Database with 1 table (Records) and 2 fields in it ("RecordID" (Number), which is the primary key, and "LowRes" (OLE Object) which is a low Resolution image). There are about 100 records.
I/m trying to load the Access Table into a DataTable (ID_Table) in VB.net.
Code so far:
Dim cnString As String = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=SBS2257_ID.accdb;"
Dim theQuery As String = "SELECT [RecordID], [LowRes] FROM [Records];"
Using CN As New OleDbConnection(cnString)
Dim command As New OleDbCommand(theQuery, CN)
Using objDataAdapter = New OleDbDataAdapter(command)
Dim ID_Table As New DataTable
CN.Open()
Dim pictureData As Byte() = DirectCast(command.ExecuteScalar(), Byte())
Dim picture As Image = Nothing
Using stream As New IO.MemoryStream(pictureData)
picture = Image.FromStream(stream)
objDataAdapter.Fill(ID_Table)
End Using
End Using
End Using
However the "DirectCast" command fails when I tell it to look at more then 1 field in my SQL statement with a datatype mismatch (if I just do [LowRes] it does not throw a error). However, I get stuck again when trying to apply the result to the table via the objDataAdapter, it doesnt fill the table with anything? I also notice that "picture" only contains the first image in the database.
I could put this database query in a function using "WHERE RECORDID=..." and loop it manually building the table returning "picture" each time, but Id like to avoid running a function 100 times, esp one that access a database.
Is it possible to read the whole database that contains images and just load it directly into a Datatable in one big swoop?
EDIT: So I got this to work:
Dim strConnection As String = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=SBS2257_ID.accdb;"
Dim strSQL As String = "SELECT [RecordID], [LowRes] FROM [Records];"
Using objConnection = New OleDbConnection(strConnection)
Using objCommand = New OleDbCommand(strSQL, objConnection)
Using objDataAdapter = New OleDbDataAdapter(objCommand)
Dim objDataTable As New DataTable("IDs")
objDataAdapter.Fill(objDataTable)
Return objDataTable
End Using
End Using
End Using
how ever when I go to view row 0, col 1 which should be the first LowRes image via a .ToString Useing this code:
Private Sub PrintValues(ByVal table As DataTable)
For Each row As DataRow In table.Rows
For Each col As DataColumn In table.Columns
MsgBox(row(col).ToString())
Next col
Next row
End Sub
It just displays "System.Byte[]". It knows its a Byte datatype, but how do I display that in a picturebox?
The ExecuteScalar() executes the query, and returns the first column of the first row in the result set returned by the query.
as your query is
Dim theQuery As String = "SELECT [RecordID], [LowRes] FROM [Records];"
the first column is RecordID which is not a Byte().
you can change your query as following:
Dim theQuery As String = "SELECT [LowRes] FROM [Records];"
or you have to use other methods to get data from the database
Dim strSql As String = "SELECT [RecordID], [LowRes] FROM [Records]"
Dim dtb As New DataTable
Using cnn As New OleDbConnection(connectionString)
cnn.Open()
Using dad As New OleDbDataAdapter(strSql, cnn)
dad.Fill(dtb)
End Using
cnn.Close()
End Using

Dynamically add listbox columns based on columns in an Access Database?

I would like to do a populate a column in my listbox for each field in my Access Database.
Right now I have to manually add the field:
QUERBOX.Columns.Add("Requestor Name", 200, HorizontalAlignment.Left)
How can I adapt my code below to automatically add columns each time I run the sub?
Dim queryString As String = "SELECT * FROM Table1;"
Dim connection As OleDbConnection
Dim command As OleDbCommand
Dim data_reader As OleDbDataReader
querbox.clear
connection = New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\apt.accdb")
connection.Open()
command = New OleDbCommand(queryString, connection)
data_reader = Command.ExecuteReader
If data_reader.HasRows Then
While data_reader.Read
Dim newitem As New ListViewItem()
newitem.Text = data_reader.GetValue(0) 'first column
newitem.SubItems.Add(data_reader.GetValue(1)) 'second column
QUERBOX.Items.Add(newitem)
End While
End If
As Plutonix suggested in comments, a DataGridView would probably be best suited, but for the sake of answering the question here's how I've done something similar:
connection.Open()
'' Fill a DataTable with all of the Column schema for the given table of 'Table1'
Dim schemaTable As DataTable = connection.GetSchema("Columns", New String() {Nothing, Nothing, "Table1", Nothing})
'' Iterate through each column in the Schema Table
For i = 0 To schemaTable.Rows.Count - 1 Step 1
'' Declare a new item for the list
Dim newItem As New ListViewItem()
newItem.Text = schemaTable.Rows(i)!COLUMN_NAME.ToString()
newItem.SubItems.Add(schemaTable.Rows(i)!COLUMN_NAME.ToString()
'' Add new item to the interface
QUERBOX.Items.Add(newItem)
Next
connection.Close()
This has helped me in projects where the user is familiar with the database structure and may need to select the fieldname as part of the business logic. For example, allowing someone with little database knowledge to standardize the records within a given field.

Joining many-to-many DataTables in VB.Net

I have 2 data sources from different source types, like:
Dim connSql As String = "Data Source=sql_src;Initial Catalog=my_db;Persist Security Info=True;User ID=usr;Password=pwd;"
Dim connOle As String = "Provider=IBMDA400;Data source=src;User Id=usr;Password=pwd"
dim qrySql as String = "Select uniqueID, name From tblSql"
dim qryOle as String = "Select name, ID From tblOle"
I place them into DataTables using functions like this (mostly for reference):
Public Shared Function sqlQryDT(qry As String, conn As String) As DataTable
Dim dt As New DataTable
Dim sqlconn As New SqlClient.SqlConnection(conn)
sqlconn.Open()
Dim adapter As New SqlClient.SqlDataAdapter(qry, sqlconn)
Try
adapter.Fill(dt)
Catch ex As Exception
Finally
sqlconn.Close()
End Try
Return dt
End Function
Public Shared Function oleQryDT(qry As String, conn As String) As DataTable
Dim dt As New DataTable
Dim cn As New OleDb.OleDbConnection(conn)
Dim cmd As New OleDb.OleDbCommand("", cn)
Dim da As New OleDb.OleDbDataAdapter(cmd)
cmd.CommandText = qry
Try
cn.Open()
da.Fill(dt)
Catch ex As Exception
Finally
cn.Close()
End Try
Return dt
End Function
Dim dtSql as DataTable = sqlQryDT(qrySql, connSQL)
Dim dtOle as DataTable = oleQryDT(qryOle , connOle)
My goal is to have a DataTable consisting of uniqueID,name,ID
(Edit) If I could do an SQL query it would look like SELECT * FROM dtSql JOIN dtOle ON dtSql.name = dtOle.name
I have tried using a DataRelation by placing the tables into a DataSet and adding a relationship on name, but since names may not be unique, this fails.
I have also tried using LINQ, but that always returns IEnumerable(System.Collections.Generic) and I can't find an easy way to place the contents into a DataTable, except by iterating through every item. And, the code is messy when there are a large number of columns.
I feel like there should be a way to do this without using a For Each loop
I looked at these question, but they didn't fully help me.
How to inner join two already filled DataTables in VB.NET
Merging 2 data tables in vb.net

Populate data from dataset and show in datagridview

I am working in VB.NET and I have a simple requirement:
I have added a MDB file to a DataSet and it contains 21 tables.
I have a DataGridView and a ComboBox on my form.
I was able to get the ComboBox populated with the table names available in the DataSet by iterating through dataset.Tables.
Now I want to the user to be able to select the table name from the ComboBox and then populate the contents of that table.
I tried the following code:
Datagridview1.DataSource = dataset1
Datagridview1.DataMember = dataset1.tables(combobox1.selecteditem)
Datagridview1.Refresh()
But I only got the column headers. Then I read that I need a TableAdapter to populate the DataSet with that table. But if I use the TableAdapter then I won't be able to populate the table in a generic way.
Currently if I have to populate TableA then I will have to create an instance of Dataset1TableAdapters.TableA and then use it's .Fill property to populate the table. I will also have to use "Dataset1TableAdapters.TableB`. Is there a generic method to populate any table in the DataSet?
The following worked for me:
Datagridview1.DataSource = dataset1.tables(combobox1.selecteditem)
C# but easily convertible to VB.Net (I suppose):
String connectionString = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=""C:\test.mdb""";
String tableName = combobox1.SelectedItem.ToString();
String sqlSELECT = String.Format("select * from [{0}]", tableName);
System.Data.OleDb.OleDbDataAdapter da = new System.Data.OleDb.OleDbDataAdapter();
da.SelectCommand = new System.Data.OleDb.OleDbCommand(sqlSELECT, new System.Data.OleDb.OleDbConnection(connectionString));
DataGridView1.DataSource = dataSet1;
DataGridView1.DataMember = dataSet1.Tables(tableName);
da.Fill(dataSet1, tableName);
I was just sketching a proof that "it can be done in a generic way" to your problem, you should elaborate and maybe come with something more elegant (and safe).
Private Sub BindData()
With customersDataGridView
.AutoGenerateColumns = True
.DataSource = customersDataSet
.DataMember = "Customers"
End With
End Sub
Just to clarify this answer. For Future Reference.
Public Class Form1
Dim con As OleDbConnection = New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\test.accdb;")
Private Sub Button1_Click
Dim da As New OleDbDataAdapter
Dim table As String = ComboBox1.SelectedItem.ToString
Dim sql As String = String.Format("select * from [{0}]", table)
da.SelectCommand = New OleDbCommand(sql, con)
DataGridView1.DataSource = DataSet.Tables(table)
da.Fill(DataSet, table)
End Sub
End Class
Not trying to Ressurect, but i thought the working version of this VB Script should be posted.
I would like to point out that the dataset is held by Visual Studio, hence the strange source string.