Data retrieval from Access file into DataTable not working - vb.net

I have some code to connect a database with the program, but for some reason at run time it does not show the data from the DB.
Public Class Form2
Dim con As New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\employee\employee.accdb")
Dim cmd As New OleDbCommand("", con)
Dim empDA As New OleDbDataAdapter
Dim empTable As New DataTable
Dim dr As OleDbDataReader
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.EmpTableAdapter.Fill(Me.EmpDataSet.emp)
Dim cmd As New OleDbCommand("select * from emp", con)
empDA = New OleDbDataAdapter("select * from emp", con)
empDA.Fill(empTable)
DataGridView1.DataSource = empDA
End Sub

The code in the question looks to be a bit muddled as to what needs to be done.
Variables should be limited to the minimum scope that they are needed in, and some things need to be disposed of after use (to avoid memory leaks, files remaining locked, and other problems with computer resources).
For the disposal, the Using statement is useful as it makes sure that that is done automatically.
You should try to put each logical piece of code in a suitably small method so that it is easier to work with. Perhaps something like this:
Imports System.Data.OleDb
Public Class Form2
Dim connStr As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\temp\employee.accdb"
Sub ShowEmployeeData()
Dim sql = "SELECT [Id], [FirstName] FROM [Employees] ORDER BY [Id]"
Using conn As New OleDbConnection(connStr)
Using cmd As New OleDbCommand(sql, conn)
Dim employees As New DataTable()
Dim da As New OleDbDataAdapter(cmd)
da.Fill(employees)
DataGridView1.DataSource = employees
End Using
End Using
End Sub
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
ShowEmployeeData()
End Sub
End Class
So the connStr variable is available everywhere in the class Form2, and the code that shows the employee data is in its own Sub.
When querying a database, you should specify the actual columns that you need, so that the columns are returned in the order you want, and order by one of the columns so that the data is returned in a predicatable order - databases are free to give you any order for anything if you don't tell them otherwise.

Ok, while you have some tips and suggestions, I'll give a few more.
First, try using the project setting to create the connection. The reason for this is not only can you create + test + make a connection, you can do this without code.
so, try this to build + create the connection:
so now click on the [...] and it will launch the connection builder for you!
So you now get this:
(use the change button if it defaulted to sql server).
So, using the above allows you to build ONE connection - one that you can use for the WHOLE application.
And there is the handy test connection button!!
So, in above we called the connection "MyDB".
That way we don't have messy connection strings in code, and we have ONE place to change/set the connection.
Now, in code?
Well, as a really nice tip?
You often need a connection
You often need a data reader.
and you need some sql (command text).
So, in place of declaring that reader, declaring the conneciton, and all that jazz?
use a command object!
Why?
because the command object has ALL of the above 3 objects in one nice simple ONE object.
As a result, you don't have to declare the 3 separate objects.
Just use and adopt a command object in MOST cases.
So, now our code has this:
Imports System.Data.OleDb
Public Class DataGridTest1
Private Sub DataGridTest1_Load(sender As Object, e As EventArgs) Handles Me.Load
Using cmdSQL As New OleDbCommand("SELECT ID, FirstName, LastName, HotelName from tblHotels",
New OleDbConnection(My.Settings.MyDB))
cmdSQL.Connection.Open()
Dim rstData As New DataTable
rstData.Load(cmdSQL.ExecuteReader)
DataGridView1.DataSource = rstData
End Using
End Sub
End Class
Note how simple - and how few variables we have to setup and declare.
So, I find this becomes quite much as easy as using Access or even writing older VB6 code.
So, try the above - its very little code, and use the connection builder in the "settings" for the application - thus removing the need to introduce connection strings all over the place in code.

Related

How to edit a record in an access database - visual basic

I want to edit a specific record in an access database but I keep on getting errors
this is the database I want to edit:
Access database
these are flashcards that the user has created and stored in an access database. What I want is that the user is able to edit the difficulty so it appears more/less often
This is the module:
Module Module1
Public Function runSQL(ByVal query As String) As DataTable
Dim connection As New OleDb.OleDbConnection("provider=microsoft.ACE.OLEDB.12.0;Data Source=flashcard login.accdb") 'Establishes connection to database
Dim dt As New DataTable 'Stores database in table called dt
Dim dataadapter As OleDb.OleDbDataAdapter
connection.Open() 'Opens connection
dataadapter = New OleDb.OleDbDataAdapter(query, connection)
dt.Clear() 'Clears datatable
dataadapter.Fill(dt) 'Fills datatable
connection.Close()
Return dt
End Function
End Module
And here is the button that the user can press to edit the database:
Private Sub btnSubmit_Click(sender As Object, e As EventArgs) Handles btnSubmit.Click
Dim sql As String
sql = "UPDATE flashcards set difficulty = '" & TxtDifficulty.Text
runSQL(sql)
End Sub
The difficulty column in the database should be able to be edited by the user through the value they entered in txtDifficulty.text
Good to hear I found the problem with the apostrophe.
I am going to need a where statement but the problem I have is that the user can create as much flashcards as they want so how would I write the where statement?
An INSERT statement does not have a WHERE clause but an UPDATE does and is usually by a primary key.
Look at how I add a new record ignoring mHasException and specifically using parameters. In this case a List is used but with little effort an array of DataRow can be passed instead.
Here is an example for updating a record with a DataRow.
To get other code samples for ms-access see the following repository.
In closing, in the above repository I don't get into all possibilities yet there should be enough there to get you going. And when reviewing code I flip between Add for adding a parameter and AddWithValue while Add is the recommend way but both are shown to see differences. see also Add vs AddWithValue.

populate a sql query into datagridview on vb.net

I wanna populate sql query on datagridview on vb.net
I tried this code that I found on internet
but I get an error
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
DataGridView2.Visible = False
Dim Dataconnection As SqlConnection
Dataconnection.ConnectionString = "server=DESKTOP-514KV5J\SQLEXPRESS;database=A;trusted_connection=True"
Dim cmd As New SqlCommand
cmd.Connection = Dataconnection
cmd.CommandText = "select SA,Product,sum(quantity) quantity from(select SA,Product,quantity from tbpurchase union all select SA,Product,-quantity from tbsold)dt group by SA,Product"
Dim rdr As SqlDataAdapter = cmd.ExecuteReader
Dim dt As New DataTable
dt.Load(rdr)
rdr.close()
DataGridView2.DataSource = dt
End Sub
I just want to view the query on datagridview2 whitout any storage on any table .
if you have a solution how can I do it .
because i have 2 tables .
1 for purchasing .
1 for selling.
and the query that i did work on ms sql well and caculates the stock still available
thanks in advance
There are two obvious issues there and, for all we know, there could be more. Firstly, you never actually create a connection object. All you do is declare a variable and then try to set the ConnectionString of an object that you never created. That's absolute programming fundamentals and nothing specific to do with data access, so that's not something we should have to explain, especially since you are creating objects later in the code so obviously know how.
Secondly, you aren't even trying to open the connection that you didn't create. If you call Fill on a data adapter then it will open and close the connection automatically but, if you use a data reader, you have to do it yourself.
With those two issues in mind and cleaning up the code somewhat, we arrive at this:
Using connection As New SqlConnection("server=DESKTOP-514KV5J\SQLEXPRESS;database=A;trusted_connection=True"),
command As New SqlCommand("SELECT SA, Product, SUM(Quantity) Quantity FROM (SELECT SA, Product, Quantity FROM tbpurchase UNION ALL SELECT SA, Product, -Quantity FROM tbsold) dt GROUP BY SA, Product", connection)
connection.Open()
Dim table As New DataTable
Using reader = command.ExecuteReader()
table.Load(reader)
End Using
DataGridView2.DataSource = table
End Using
For objects that support it, you should always create them with a Using block if you are only going to use them then and there, because they will be implicitly disposed at the End Using line. It is also preferable to pass arguments to constructors rather than call parameterless constructors and then set properties immediately after.

Issues to make DataSet Public

I'm familair with VBA/SQL programming in a excel environment. I'm recently started to get acquainted with vb.net but I'm strugling with a number of topics. One of these topics relates to public DataSet handling. Hope someone can help with this.
I defined a Module with the below VB code with the attempt to create a (public accesable) DataSet:
Imports System
Imports System.Data
Imports System.Data.SqlClient
Module Module1
Public ds As DataSet
Public Sub CRMds()
Dim con As SqlConnection
con = New SqlConnection("Server=MI5047LT\DELIMA01;Initial Catalog=CRM01;Integrated Security=SSPI")
Dim str As String = "SELECT * FROM CRM01Main"
Dim cmd As New SqlCommand(str, con)
Dim da As New SqlDataAdapter(cmd)
Dim ds As New DataSet()
da.Fill(ds, "CRM01Main")
con.Close()
con = Nothing
End Sub
End Module
Within the above module (code not show) I'm also verifying if the DataSet is correctly populated (returns a correct DataSet population).
When I'm Loading a Form(1) I'm calling this module with a verification step checking if DataSet is correctly populated:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
call Module1.........
varXX = ds.Tables("CRM01Main").Rows(0)("Contact_ID").ToString
MsgBox(varXX)
End Sub
("Contact_ID" is the SQL Column Name)
The error message appears when running this application:
System.NullReferenceException: 'Object reference not set to an
instance of an object
apperatly meaning no values are populated in this DataSet(?).
Note: When I run this procedure with a "single variable (e.g. Var="OK") this variable is visible in any form opened.
Main Objective is to populate a initial created DataSet (through Module1) over multiple forms.
I'm realize above query is most probably a very basic issue but unfortunately I'm strugling for a number of weeks to figure out the correct code or procedure. Any help would ne highly appreciated.
This has got nothing to do with anything being Public and everything to do with scope. If you already have this:
Public ds As DataSet
then what is this for:
Dim ds As New DataSet()
If you had a rubbish bin outside your house and then you put a rubbish bin in your bedroom and threw some rubbish in it, would you expect that rubbish to magically appear in the rubbish bin outside? I would expect not.
If you expect to get something from that ds member variable then you need to assign something to it, not to a different variable declared locally within a method that ceases to exist when that method completes.
You should do some reading on the difference between local variable and member variables (fields).
EDIT:
To be explicit, don't declare a new variable and assign to that but rather assign to the existing variable:
ds = New DataSet()
Dim in vb.net is used to Dimension (Declare) a local variable. The compiler will look for the closest scope first for a variable. If the compiler finds a local variable it stops looking and that is the variable it uses.
If an Object has a .Dispose method, it should be called. For example, connections in ADO.net may have unmanaged code that needs to be cleaned up. Classes may be doing that clean up in the .Dispose method. Setting an object to Nothing does not accomplish this clean up in a timely manner. Using...End Using blocks were created to handle this for you. Notice that 3 ADO.net objects are in a single Using block separated by commas. The resource will be closed and disposed even if there is an error.
Public ds As DataSet
Public Sub CRMds()
Using con As New SqlConnection("Server=MI5047LT\DELIMA01;Initial Catalog=CRM01;Integrated Security=SSPI"),
cmd As New SqlCommand("SELECT * FROM CRM01Main;", con),
da As New SqlDataAdapter(cmd)
ds = New DataSet()
da.Fill(ds, "CRM01Main")
End Using
End Sub

CommandText Property Has Not Been Initialized, retrieving data

Private Sub ButtonSubmitID_Click(sender As Object, e As EventArgs) Handles ButtonSubmitID.Click
Dim comm As New SqlCommand
Dim conn As New SqlConnection
conn.ConnectionString = "Data Source = localhost\SQLEXPRESS; Initial Catalog = test2Forms; Integrated Security = SSPI;"
comm.Connection = conn
Dim ID = TextBoxID.Text
comm.Parameters.AddWithValue("#ID", ID)
Dim adapter As SqlDataAdapter = New SqlDataAdapter(comm.CommandText, comm.Connection)
comm.CommandText = "SELECT * FROM withActivityLog3 WHERE ID = #ID"
Dim records As DataSet = New DataSet
adapter.Fill(records)
DataGridView2.DataSource = records
End Sub
CommandText property has not been initialized is the error I am receiving. I am able to pull all the data from the database into the GridView on the Form Load but when I try to narrow it down to one ID using a WHERE clause on the button trigger, it comes up with the above error. I've used the debugger to trace through one step at a time and the command and connection strings look correct. I've also successfully duplicated the query on my database using the SQL Server command line. I'm searching on a primary key (ID) so the expected results would be one uniquely identified row from the database.
As for the problem you know you have:
' initialize DataAdapter with (EMPTY) commandtext
Dim adapter As SqlDataAdapter = New SqlDataAdapter(comm.CommandText, comm.Connection)
' initialize Command Text
comm.CommandText = "SELECT * FROM withActivityLog3 WHERE ID = #ID"
When you pass the CommandText to the DataAdapter, it is empty because you havent set it yet which results in the error.
There is a fair amount of inefficiency in your code though. Rewritten:
' form level conn string
Private TheConnString As String = "Data Source = localhost\..."
Private Sub ButtonSubmitID_Click(sender ...
Dim dt As New DataTable
Using dbcon As New MySqlConnection(TheConnString)
Using cmd As New MySqlCommand("select * from Sample where Id = #id", dbcon)
cmd.Parameters.Add("#id", MySqlDbType.Int32).Value = Convert.ToInt32(TextBox2.Text)
dbcon.Open()
dt.Load(cmd.ExecuteReader)
dgvA.DataSource = dt
End Using
End Using
End Sub
Note: this uses MySQL but the concepts are the same for Sqlite, Access, SQL Server etc
There is no need to type or paste the connection string and over everywhere it is used. One form level variable will allow DRY (Dont Repeat Yourself) code.
Anything which implements the Dispose() method should be disposed of. That includes nearly all the DB Provider objects. The Using statement allows you to declare and initialize an object and at the End Using it is disposed of. Failing to Dispose of things can cause leaks and even run out of connections or resources to create things like DB Command objects.
There is no need to create a local DbDataAdapter. These are very powerful and useful critters meant to do much more than fill a DataTable. If that is all you are doing, you can use ExecuteReader method on the DbCommand object.
Nor do you need a local DataSet. Contrary to the name, these do not hold data, but DataTables. Since there is only one and it is local (goes out of scope when the method ends), you dont need a DataSet to store it.
The Add method should be used rather than AddWithValue. The code above specifies the datatype for the parameter so there is no guesswork required of the compiler. Of course with that comes the need to convert the text to a number...
...Since this is user input, you should not trust the user, so Integer.Tryparse would be more appropriate: I like pie will not convert to an integer. Data Validation is something you should do before you commence the DB ops.
Dim ID = TextBoxID.Text as used is pointless code. You do not need to move the textbox text into a new variable in order to use it. However, ID might be used to store the integer value

I am trying to alphabetize a combo box using a query in my vb code. How do i get it to work Im having problems?

I want to know if its possible to somehow use a query in my vb code to alphabetize a list in a combo box that I have a dataset connected to?
Here is my code:
Private Sub ValueSourceAvailabilityBindingNavigatorSaveItem_Click(sender As Object, e As EventArgs) Handles ValueSourceAvailabilityBindingNavigatorSaveItem.Click
Me.Validate()
Me.ValueSourceAvailabilityBindingSource.EndEdit()
Me.TableAdapterManager.UpdateAll(Me.ValueTrackerDataSet)
End Sub
Private Sub Form3_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'TODO: This line of code loads data into the 'ValueTrackerDataSet3.SA_CountryCode' table. You can move, or remove it, as needed.
Me.SA_CountryCodeTableAdapter.Fill(Me.ValueTrackerDataSet3.SA_CountryCode)
'TODO: This line of code loads data into the 'ValueTrackerDataSet2.SA_Client' table. You can move, or remove it, as needed.
Me.SA_ClientTableAdapter.Fill(Me.ValueTrackerDataSet2.SA_Client)
'TODO: This line of code loads data into the 'ValueTrackerDataSet1.Cubes' table. You can move, or remove it, as needed.
Me.CubesTableAdapter.Fill(Me.ValueTrackerDataSet1.Cubes)
'TODO: This line of code loads data into the 'ValueTrackerDataSet.ValueSourceAvailability' table. You can move, or remove it, as needed.
Me.ValueSourceAvailabilityTableAdapter.Fill(Me.ValueTrackerDataSet.ValueSourceAvailability)
End Sub
Private Sub ClientIDComboBox_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ClientIDComboBox.SelectedIndexChanged
SELECT *
FROM dbo.SA_Client
ORDER by ClientName
End Sub
End Class
You can't just put a SQL statement inside of a VB .Net sub like that. You need to either use LINQ/Entity Framework, or format the query as a string and send it to SQL. The first method would depend on how your entity is set up, while the second method would look something like this:
'The SQL Connection
Dim sqlLConn As New SqlConnection()
'The SQL Command
Dim sqlCmd As New SqlCommand()
'Set the Connection String
sqlConn.ConnectionString = "connection string goes here"
'Open the connection
sqlConn.Open
'Set the Connection to use with the SQL Command
sqlCmd.Connection = SQLConn
' Set your query
sqlCmd.CommandText = "SELECT * FROM dbo.SA_Client ORDER by ClientName"
' DO STUFF WITH THE sqlCmd query here...
'Close the connection
sqlConn.Close()
First option: You can do it programatically by your sql Query
SELECT * FROM tableName ORDER BY columnName ASC/DESC
second option by settiong the Sorted option to TRUE
Would it solve your problem if the data you retrieved from the database already had the data sorted in ClientName order? In that case, you'll need to change the SQL associated with the Fill method on your SA_ClientTableAdapter data adapter.
If you need to sort the data separately from the DataSet and DataTable, you have a couple of options.
You can use LINQ, and bind to a sorted version of your data. Rather than binding directly to the DataSet or DataTable, you'd bind to an expression:
[whatever you're binding] = Me.ValueTrackerDataSet2.SA_Client.OrderBy(c=>c.ClientName)
You can use a DataView over the DataTable, which is (one of) the older ways we used to do this:
Dim dv as DataView = New DataView(Me.ValueTrackerDataSet2.SA_Client, "", "ClientName", DataViewRowState.CurrentRows)
[whatever you're binding] = dv