VB.net Getting Scalar to save a value to a variable - sql

I've been looking through the forums with no luck. I am trying to retrieve a value from a database and store it to a variable. The closest I got was following This. Here is my Code:
Dim dblAircraftHourlyRate As Double
Dim intAircraftID As Integer
intAircraftID = ddAircraft.SelectedItem.Value
Dim mySqlComm As String = "SELECT HourlyRate FROM Aircraft WHERE AircraftID = '" & intAircraftID & "'"
Using cn As New SqlConnection("Data Source=.\SQLEXPRESS;AttachDbFilename=C:\Users\Rollin Laptop\Desktop\CurrentAll2Fly3\App_Data\ASPNETDB.MDF;Integrated Security=True;User Instance=True"), _
cmd As New SqlCommand(mySqlComm, cn)
cn.Open()
dblAircraftHourlyRate = Convert.ToDouble(cmd.ExecuteScalar())
End Using
I'm not sure why, but instead of saving the HourlyRate to the dblAircraftHourlyRate, it is saving the intAircraftID to dblAircraftHourlyRate. I'm also not sure why the example code did not close the database connection. Any ideas on how to fix this to get the correct variable?

My solution had nothing to do with the question, but I had a separate bit of code that was executing after the bit I posted. It was resetting the value of dblAircraftHourlyRate such that dblAircraftHourlyRate = ddAircraft.SelectedItem.Value After I commented out the line, the code worked perfectly. To clarify, the value in the dropdownlist was the AircraftID, not the HourlyRate.
Tim Schmelter also helped me out in his explanation of how Connection-Pooling works:
Connection-Pooling is enabled by default. Default means that it's enabled even if you don't specify the Pooling parameter in your connection-string. Connection-pooling helps to improve performance since it maintains the state of the physical connections. So even if you close a connection the physical connection keeps open (If you check it in the database). You are using the Using-statement which is best practise. Disposing a connection will "close" it. – Tim Schmelter

Related

Additional information: There is already an open DataReader associated with this Command which must be closed first. vb.net

Dim cat As New Catalog()
Dim con As New OleDbConnection()
Dim cmd As New OleDbCommand
Dim ds1 As New DataSet
Dim conn As ADODB.Connection
' Open the Access database.
conn = New Connection
conn.ConnectionString =
"Provider=Microsoft.Jet.OLEDB.4.0;" &
"Data Source=" + openExcel + "\Test" + ".mdb; Persist Security Info=False"
con.ConnectionString =
"Provider=Microsoft.Jet.OLEDB.4.0;" &
"Data Source=" + openExcel + "\Test" + ".mdb; Persist Security Info=False"
conn.Open()
xlWorkSheet1.Columns(5).Insert
Dim cellValue As String = ""
Dim newValue As String = ""
Dim sh1 As String = ""
Dim qty As String = ""
Dim matchText As String = ""
Dim sql As String = ""
con.Open()
sh1 = LTrim$(xlWorkSheet1.Cells(i, 1).Text)
sql = "SELECT Num_ber, Q_ty FROM good WHERE Na_me LIKE 'staff%' And Ty_pe = 'ORD'"
Dim cmd As New OleDbCommand(sql, con)
Dim myReader As OleDbDataReader = cmd.ExecuteReader()
conn.Execute(sql)
myReader = cmd.ExecuteReader() ' HERE'S THE PROBLEM
xlWorkSheet1.Cells(1, 5) = myReader.GetString(0)
xlWorkSheet1.Cells(1, 11) = myReader.GetString(1)
myReader.Close()
conn.Close()
conn = Nothing
**I wanted to retrieve a specific value from mdb and then write it to excel.
Here's my code, I got this error so many times and I can't find it out. Can anybody help me? Thanks.**
[1]: https://i.stack.imgur.com/6Fuvg.png
Ok, you first have to decide when usng .net what "provider" you are going to use, AND THEN decide what kind of data objects you want to use.
You can use a oracle provider, a sql server provider, or in this case, since we using Access, then we can use EITHER oleDB, or ODBC. Either choice is fine. Most use oleDB providers for Access, but often ODBC is a good choice, especially if down the road you plane to swap out Access for say SQL server.
What the above means in plain English?
You don't want to adopt the external ADODB code and library. That code is NOT .net, and thus you REALLY but REALLY do not want to write your .net code that way. ADODB was written LONG before .net, and is what we call un-managed code (non .net). I strong, but strong suggest you do NOT add a reference to ADODB to your project, and I beyond strong recommend you avoid introduction of a non .net library for doing this!!! We certainly can adopt the oleDB provider in .net, but we will NOT have a direct reference to JET/ACE (the access database engine) in our applcation. As noted, there are some exceptions to this suggesting, but they don't apply to you and here.
Next up:
The design pattern in .net is to create the connection, get the data, and CLOSE the connection. This "pattern" will then be 100% sure that the data base is always closed, and you NEVER have to worry about if the connection is open, closed, or even if you forgot to close the connection!!! So, do this correct, and some "open" connection will never bite you, or will you have to worry about this issue.
You can in some operations keep the connection open for performance, but lets learn to walk before we run so to speak.
next up:
We certainly do NOT want to place and have connection strings all over in our code. Not only is this going to wear out your keyboard, but if you ever need to change the connection, then you going to have to hunt down all that code.
Best to let Visual Studio save that connection in ONE location, and MORE important MANAGE this for you!!!
Next up:
Do you ONLY need to work with mdb files, or do you plan/need to work with accDB files? This is a HUGE issue, and one that you cannot ignore.
next up:
Are you going to use the x32 bit version of the Access database system, or the x64 bit version?
Since your example posted code uses JET (access data engine for mdb files ONLY x32 bit version)?
Then this ALSO means you MUST (and I repeat MUST) force your .net project to run as x32 bits. You cannot use "any cpu", and you cannot use x64 bits, you MUST choose x86 bit size for your .net project. Failure to do so will result in the project not working.
Ok, with the above information?
First up, force/set/be 100% sure your project is set to run as x32 bits.
That setting is this one:
and remove the reference you have to ADO if you created one.
Ok,
next up:
Create the connection to the database.
Project ->properties.
This here:
And then:
and then
Now, you can browse, and select the access mdb file.
But, you MUST not skip the next step - you have to choose JET (older, mdb files), or choose the newer ACE (for accDB format files).
So, this:
now this:
As noted, you choose JET or ACE here.
now, we have this and you can use test connection.
BUT BE VERY careful!!!!
If you are using vs2022, then keep in mind vs2022 is the FIRST version of VS that is now x64 bits. As a result, vs can't pass the test connection!!! Your connection is in fact ok, but will fail with vs2022.
If you using a previous version of VS (before 2022), then the test connection button should work. and you see this:
Ok, now that we have a valid working conneciton setup, we can now write code, and we will NOT use ADODB!!!!
The typical code pattern to read and load a data table (like a access VBA recordset) will be like this:
Now, I became RATHER tired of writing that same using block over and over. So, in a global module, I have this code now:
Public Function MyRst(strSQL As String) As DataTable
Dim rstData As New DataTable
Using conn As New OleDbConnection(My.Settings.AccessDB)
Using cmdSQL As New OleDbCommand(strSQL, conn)
conn.Open()
rstData.Load(cmdSQL.ExecuteReader)
End Using
End Using
Return rstData
End Function
So, now with the above handy dandy helper routine?
Your code becomes this:
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim Sql As String =
"SELECT Num_ber, Q_ty FROM good WHERE Na_me LIKE 'staff%' And Ty_pe = 'ORD'"
Dim rstData As DataTable = MyRst(Sql)
Debug.Print("Na_me is " & rstData.Rows(0).Item("Na_me"))
End Sub
Or, display all return rows from that data table
Debug.Print("Na_me is " & rstData.Rows(0).Item("Na_me"))
For Each OneRow As DataRow In rstData.Rows
Debug.Print("na_me = " & OneRow("Na_me"))
Next
So, you really don't need (or want) a reader anyway. Just load the results into a nice clean, easy to use data table, and from that you can loop the table, grab rows, or do whatever you want.

Getting an E_OUTOFMEMORY when accessing an Access database with OLEDB

We have this VB.net code that connects to an MS Access Database and tries to insert a new entry:
Dim conn As New OleDbConnection
conn.ConnectionString = "Provider="Microsoft.ACE.OLEDB.16.0; Data Source=" & DATABASE_PATH & ";Jet OLEDB:Database Password=pass;"
conn.Open()
Dim SqlString As String = "INSERT INTO tblNotes" &
" ([NotesNumber" &
"], [NotesTitle" &
"], [HasAdditionalLogic" &
"], [TypeId]) Values (?,?,?,?)"
Dim cmd As New OleDbCommand(SqlString, conn)
cmd.CommandType = CommandType.Text
cmd.Parameters.AddWithValue("NotesNumber", 1234)
cmd.Parameters.AddWithValue("NotesTitle", "the title")
cmd.Parameters.AddWithValue("HasAdditionalLogic", False)
cmd.Parameters.AddWithValue("TypeId", 14)
cmd.ExecuteNonQuery()
conn.close()
Nothing too fancy, right?
This code worked fine with Access 2016 installed.
Now with the recent upgrade to Office 365 the line
cmd.ExecuteNonQuery()
causes this error:
'Microsoft.ACE.OLEDB.16.0' failed with no error message available, result code: E_OUTOFMEMORY(0x8007000E)
Googling for that error message lead to several ideas like using Integer instead of Long Integer in the database, but that did not help either.
And personally, I doubt that the root cause is a lack of memory because the machine has 32GB RAM installed and is set to 32GB of Virtual Memory. The process itself never uses more than 100MB, Windows Process Explorer tells us that the whole RAM uses about 5GB total. So I just cannot believe we are actually running out of memory here.
Any idea?
Update:
Okay, we seem to have found the underlying issue here.
You see this line:
cmd.Parameters.AddWithValue("TypeId", 14)
In the Access database, the field "TypeId" has been defined as a Primary Key of Data Type "AutoNumber" and Field Size "Long Integer".
Now, if we write the code like this:
cmd.Parameters.AddWithValue("TypeId", 14I)
it runs without an error, but as soon as we change it to:
cmd.Parameters.AddWithValue("TypeId", 14L)
we get the crash.
Let me state again that the code with a Long works fine with Access 2016, it crashes with the Access from Office 365.
I may be mistaken, but this seems like a bug in Access.
Of course we can now change all the app code from Long to Integer (or UInteger), but this seems like treating the symptoms instead of the root cause.
Can somebody confirm this? Or tell me why exactly this happens? Using a Long seems to be correct to me, using an Integer instead seems pretty wrong to me.
To anybody who might face the same problem: we "fixed" the issue by installing "Microsoft Access Database Engine 2010 Redistributable"
https://www.microsoft.com/en-US/download/details.aspx?id=13255
and then using
Microsoft.ACE.OLEDB.12.0
instead of
Microsoft.ACE.OLEDB.16.0
That did the trick.
The hint with .add instead of .addWithValue did not make any difference.

Read Value from Database in TextBox when Combobox text changes VB.NET

I have a list of Users Names in ComboBox and Some TextBoxes. When ComboBox text changes (i.e I select some username from ComboBox), The TextBoxes are filled with user details from the database.
I have code to achieve this in SQL Database. But these queries are not working with MsAccess database.
MysqlConn = New MySqlConnection
Mysql.ConnectionString = "server=localhost;user=root;password=root;database=database"
Dim READER As MySqlDataReader
Try
MysqlConn.open()
Dim Query As String
Query("select * from database.usernames where name='" & ComboBox1.Text & "'")
Command = New MySqlCommand(Query, MysqlConn)
READER = Command.ExecuteReader
While READER.Read
TextBox1.Text = READER.GetString("name")
End While
End Try
Here is my answer. Please don't get overwhelmed by it. ;)
Broken code
First of all, as I see it, the code you provided cannot work at all, because:
your Query variable is initialized in an invalid (or at least a very exotic) way. You probably want to use something like:
Dim Query As String
Query = "select * from database.usernames where name='" & ComboBox1.Text & "'"
or in a single line:
Dim Query As String = "select * from database.usernames where name='" & ComboBox1.Text & "'"
you try to assign the connection string to the ConnectionString property of a nonexistent Mysql variable. Or the variable exists because it is declared somewhere else, which might be a bug in your code snippet here. But I assume you want to assign the connection string to the MysqlConn.ConnectionString property instead.
you have not declared the MysqlConn and Command variables anywhere. You only just assign to them. (I will simply assume you have declared the variables correctly somewhere else in your code...)
the IDataRecord interface does not provide a GetString(name As String) method overload. So unless you have defined a custom extension method for it, you probably need to use the IDataRecord.GetOrdinal(name As String) method as well, or use the column index instead of the column name.
Anyway, the code you provided uses MySQL. So I assume that MySQL is the "SQL Database" you are using successfully. And that seems to work, as you say? Well... Hmmm... Then I will simply assume your code snippet is completely correct and works perfectly with MySQL... :/
MS Access vs. MySQL
Using MS Access requires other data access classes (probably the ones in namespace System.Data.OleDb) and another connection string. You could take a look at this ADO.NET OleDb example for MS Access in the Microsoft documentation.
You probably even have to update your SQL query, because every database system uses its own SQL dialect. You might want to consult the Office documentation for that. But your query is quite simple, so perhaps all you have to do to make it work with MS Access is:
remove the database name and use only the table name, and
delimit the name identifier (since it is a reserved keyword in MS Access).
I personally delimit all identifiers in my SQL queries, just to avoid unintended conflicts with reserved keywords. So I would personally use something like this:
select * from [usernames] where [name] = '...'
Additional tips
Also, I would like to provide you some additional (unrelated) tips regarding improving your code:
Use Using-statements with variables of an IDisposable type as much as possible. Those types/classes do not implement that interface if there isn't a good reason for it, so I consider it not unimportant to call Dispose when you are done with such disposable objects (or using a Using statement to call Dispose implicitly).
Use SQL parameters (if possible) to avoid SQL injection vulnerabilities. Look at this StackOverflow question and its answer for an example of how to use SQL parameters with MS Access.
Example
You may take a look at the following code snippet. It might not provide a working example out-of-the-box, but you might get some useful/practical ideas from it:
Dim connectionString As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\Data\\database.mdb;User Id=admin;Password="
Dim query As String = "select * from [usernames] where [name] = #Name"
Using conn As New OleDbConnection(connectionString)
Using command As New OleDbCommand(query)
command.Parameters.Add("#Name", OleDbType.VarChar, 50).Value = ComboBox1.Text
conn.Open()
Using reader As OleDbDataReader = command.ExecuteReader
If reader.Read Then
textbox1.Text = reader.GetString(reader.GetOrdinal("name"))
End If
End Using
End Using
End Using

SQLite database file can't be opened when placed in network folder

Can someone help me to understand why this works fine...
Dim cs = "Data Source=C:\folder\Livros.sdb;Version=3;"
Dim cn = New System.Data.SQLite.SQLiteConnection(cs)
cn.Open() ' no exception
... while this breaks when opening connection (it is exactly the same file)...
Dim cs = "Data Source=\\NetworkServer\folder\Livros.sdb;Version=3;"
Dim cn = New System.Data.SQLite.SQLiteConnection(cs)
cn.Open() ' exception: {"unable to open database file"}
... and fix it because I need to place database file in network location so I can access it regardless of the computer I run the application?
Thank you very much!
Ok, so by trial and error I found the solution, although I can't quite understand the reason it works:
Dim cs = "Data Source=\\NetworkServer\folder\Livros.sdb;Version=3;"
Dim cn = New System.Data.SQLite.SQLiteConnection(cs)
cn.ParseViaFramework = True ' JUST ADDED THIS STATEMENT
cn.Open() ' no exception
If somebody can explain why .ParseViaFramework = True does the trick, please feel free to comment.
Similar question was asked here.
SQLite: Cannot open network file programmatically, even though worked before
The top answer gives a few more fixes. Linking here as this is the first stackoverflow that came up when I searched. Also I was using a SQLiteConnectionStringBuilder and could not find a way to set the parseViaFramework so the first solution was the one I needed.
Double the leading two backslashes in the file name (e.g. "\\\\network\share\file.db").
Use a mapped drive letter.
Use the SQLiteConnection constructor that takes the parseViaFramework boolean argument and pass 'true' for that argument.

How to populate a combobox in vb.net with filtered data from an msaccess table

I would really appreciate any help I can get.
My problem is that I have Combobox1 bound to a BindingSource and the DataMember and ValueMember property linked and working. For the life of me I do not know how to use the value (selected valuemember) of Combobox1 to filter the results I show on Combobox2. I am desperate for a simple way to do this.
my failing code is below
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
Dim conn As New SqlConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|\Database1.mdb") 'This line fails
Dim strSQL As String = "SELECT * FROM Questions WHERE Section='" & ComboBox1.ValueMember & "'"
Dim da As New SqlDataAdapter(strSQL, conn)
Dim ds As New DataSet
da.Fill(ds, "Disk")
With ComboBox2 'Here i try to populate the combobox2
.DataSource = ds.Tables("Questions")
.DisplayMember = "Question_String"
.ValueMember = "Question_Code"
.SelectedIndex = 0
End With
End Sub
I keep getting a system level error as follows
{"Keyword not supported: 'provider'."}
I have tried a few other options but the errors I get seem more cryptic can someone please help me on this. I will appreciate it a lot.
Dim conn As New OleDBConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source='|DataDirectory|\Database1.mdb'")
Also your query has to use a string not an object so try...
Dim strSQL As String = "SELECT * FROM Questions WHERE Section='" & ComboBox1.ValueMember.toString & "'"
Because you are using a Provider for a connection that doesn't need it because the provider should be an SQL driver.
I don't know what database you are using (well, the file is an access file), but you need to check you have the correct connection string
see http://www.connectionstrings.com/sql-server-2008#p2
Here are a couple of observations about your code that I hope you find helpful:
First, you might want to look at this MSDN help on how to move your database connection string out of the code and into a configuration file. This is especially important for your code to work to work more seemlessly across different environment (dev box, staging, production, etc) - Connection Strings and Configuration Files (ADO.NET)
I also noticed that you never explicitly open or close the connection. Per this entry on stack overflow, you should be ok, but keep in mind that if you happen to change the code to explicitly open the connection you will also need to close it.
I also noticed that you aren't using a parameterized query. This makes your code vulnerable to a SQL Injection attack. Here is a link to a blog posting by Scott Guthrie 'Tip/Trick: Guard Against SQL Injection Attacks'. You never know who may copy and paste your block of code with this bad practice.
Finally, you do the following query (with appropriate mods from other answers:
Dim strSQL As String = "SELECT * FROM Questions WHERE Section='" & ComboBox1.ValueMember.toString & "'"
And subsequently only use Question_String, and Question_Code in your code. You might want to consider changing your query to only pull the columns you need. This is especially helpful when you have tables with many columns. Otherwise you will needlessly pull data your code never actually needs. So your query would become:
Dim strSQL As String = "SELECT Question_String, Question_Code FROM Questions WHERE Section='" & ComboBox1.ValueMember.toString & "'"