CommandText Property Has Not Been Initialized, retrieving data - vb.net

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

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.

Data retrieval from Access file into DataTable not working

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.

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.

VB is not a member of 'String'

Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextSearch.TextChanged
'attempting to allow search by last name
Dim con As New OleDb.OleDbConnection
Dim cmd As New OleDb.OleDbCommand
Dim Sql As String
Dim data_reader As String
con.ConnectionString = "PROVIDER = Microsoft.ACE.OLEDB.12.0;Data Source=C:\Me._DeCON_12___2015DataSet.DeCon"
con.Open()
Sql = "SELECT [First Name 2015], [Last Name 2015] FROM DeCon WHERE [Last Name 2015] = TextBoxLName.Text"
data_reader = Sql.ExecuteReader()
'ListBox1.Items.Clear()
If data_reader.HasRows = True Then
Do While data_reader.Read()
lbfirstname.item = data_reader.Item("firstname")
Loop
End If
data_reader.Close()
data_reader = Nothing
con.Close()
End Sub
Okay I'm a total newbie, and I'm trying to make it so a user can search by last name in a textbox, and then have first names (of people with that last name) show up in a listbox. I was given this code (except for data_reader As String) and I know I can make it work, but I don't know how.
Here are the errors I'm getting:
'ExecuteReader' is not a member of 'String'.
'Has Rows' is not a member of 'String'.
'Read' is not a member of 'String'.
'lbfirstname' is not declared. It may be inaccessible due to its protection level.
'Item is not a member of 'String'.
'Close' is not a member of 'String'.
Now...lbfirstname, I might be able to figure out. I assume I need to change the name to whatever makes sense. Is it referring to the textbox or the listbox?
The rest of it...I have no idea. I thought Close was a given, and assumed Read was. When I try to Dim * As String it's of no help, and I knew that wouldn't be right anyway. I'm connecting to an Access database, if that makes any difference.
I don't know enough VB to do so. I was voluntold to make it, and somehow managed most the other bits with little help. This is the last part I should have to do, and I need it done by tomorrow.
The errors you are getting are because you're attempting to call properties and methods that are not part of the String class, as has been mentioned in the comments. Specifically:
ExecuteReader is a method of OleDbCommand.
HasRows is a property of OleDbDataReader (which is returned by calling OleDbCommand.ExecuteReader(). Read() and Close() are methods on the OleDbDataReader.
lbfirstname is not the ID assigned to the ListBox control in your application - you need to use the ID you gave the control.
Item should probably be Items (note the plural), referring to the collection of items in the ListBox.
You're vulnerable to SQL injection (in addition to the fact that your SQL string won't work anyway, because you use TextBoxLName.Text as a literal when you want the value of the TextBox instead. To avoid SQL injection, you should be using parmaterized queries.
lbfirstname.item = data_reader.Item("firstname") - Even if this line of code worked, you'd only wind up with the last firstname in the collection returned from your database. You need to add the first names to the ListBox via the Add method.
Putting this altogether, you would have something like this:
Using con As New OleDb.OleDbConnection("PROVIDER = Microsoft.ACE.OLEDB.12.0;Data Source=C:\Me._DeCON_12___2015DataSet.DeCon")
con.Open()
Dim Sql As String = "SELECT [First Name 2015], [Last Name 2015] FROM DeCon WHERE [Last Name 2015] = #LastName"
Dim cmd As New OleDb.OleDbCommand(Sql, con)
cmd.Parameters.Add("#LastName", OleDb.OleDbType.VarChar).Value = TextBoxLName.Text
Using data_reader As OleDb.OleDbDataReader = cmd.ExecuteReader()
If data_reader.HasRows Then
Do While data_reader.Read()
lbfirstname.Items.Add(data_reader.GetString(0))
Loop
End If
End Using
End Using
Explanation of the above code:
First, the connection is wrapped in a Using block - this will ensure the connection is properly closed and disposed of when the block is exited, even if an exception is thrown.
Next, the Sql string is parameterized by replacing the value in the WHERE clause with #LastName. The OleDbCommand is created and assigned the Sql string plus the OleDbConnection object.
The #LastName parameter is then added to the command's Parameters collection and assigned the value of the TextBoxLName.
ExecuteReader is then called on the OleDbCommand object, in a Using block again (to ensure the reader is properly closed and disposed of).
While the reader is looped through, the first name of each record returned from the query is added to the ListBox. I used the GetString method of the reader to return the value as a string. This method requires an ordinal (the index of the column), which based on your provided SQL string is the first column (0 since it's 0-indexed).
All of the above code assumes the column names in the query are correct and the control names are correct - you may need to adjust them to match what you have in your application.

Fill Datatable using SQL 'select' WITHIN A TRANSACTION

I would like to fill a datatable with results from a SQL select statment but using a transaction. The reason that I am using a transaction is because I have a list of names (as a datatable), and I want to iterate through the list of names and select the database rows where the name = the name on the list. There are 500,000 names in the database and I only want to retreive the relevant rows. I have the code for the procedure as I think it should look like (untested) BUT I dont know HOW to place the data into a datatable .... so Im missing something where I declare the datatable and the 'fill' of that table , could someone help with this ? Or suggest how else I can get the information out of the batabase without looking up each name individually.
Using connection As New SQLite.SQLiteConnection(R2WconectionString)
connection.Open()
Dim sqliteTran As SQLite.SQLiteTransaction = connection.BeginTransaction()
Try
oMainQueryR = "SELECT NameID, Address, Ocupation FROM Employees Where Name= :Name"
Dim cmdSQLite As SQLite.SQLiteCommand = connection.CreateCommand()
With cmdSQLite
.CommandType = CommandType.Text
.CommandText = oMainQueryR
.Parameters.Add(":Name", SqlDbType.VarChar)
End With
'Prevent duplicate selects by using a dictionary
Dim NameInalready As New Dictionary(Of String, String)
For Each row As DataRow In TheLIST.Rows
If NameInalready.ContainsKey(row.Item("Name")) Then
Else
NameInalready.Add(row.Item("Name"), "")
cmdSQLite.Parameters(":Name").Value = row.Item("Name")
cmdSQLite.ExecuteNonQuery()
End If
Next
sqliteTran.Commit()
Catch ex As Exception
End Try
End Using
First, you don't need a transaction because you aren't updating the database.
Second, depending on the possible number of Names in TheLIST, it might be worthwhile for you to change the name selector to IN (i.e. SELECT * FROM Employees WHERE Name IN ('name1', 'name2'). However, if you expect more than about 10, this is probably not worth trouble.
Finally, you need to create a new DataTable to hold the results. Then you need to create a DataAdapter passing cmdSqlLite as the constructor parameter. And finally, replace your ExecuteNonQuery with DataAdapter.Fill(DataTable).
For example (after Dim cmdSQLite):
Dim oDataTable As New DataTable("Employees")
Dim oAdapter As New SqliteDataAdapter(cmdSQLite)
and replacing the ExecuteNonQuery line with:
oAdapter.Fill(oDataTable)
I will qualify this code by saying it may need some tweaks. I only work with class objects and collections, so my preference would have actually been to load a collection of Employee class instances.
I would have done that by replacing ExecuteNonQuery with ExecuteReader and then the loading the read data into a new class instance. This type of approach resolves various issues with serializing the data across service boundaries (i.e. Xml for web services) and also lets you embed business logic, if needed, into the classes.