Multiple Database connections within 1 application - VB .NET - sql

This may have been answered but my search hasn't found what I was looking for.
Basically, I am developing an application which allows the user to build a query at design time, i.e. for users with no prerequisite knowledge of SQL
The application thus far allows the user to select which table(s) from the database they wish to start querying (I won't go into the details of the rest for now)
My confusion is this; I already have the connection to the database in a subroutine which obtains the schema information and filters it to display only the available tables within the database, which then compiles the data into a listbox, here is that sub:
Public Sub getSchemaInfo()
Dim ds As New DataSet
Dim dt As New DataTable
Dim con As New OleDbConnection
Dim strDatabaseLocation As String = Application.StartupPath
Dim da As New OleDbDataAdapter
Dim i As Integer
'ds.Tables.Add(dt)
con.ConnectionString = "Provider=microsoft.jet.oledb.4.0; data source = " & strDatabaseLocation & _
"\EmployeeDepartment.mdb"
'clear listbox of any data first
frmAddTable.lbTables.Items.Clear()
'Try catch block used to handle connection errors gracefully
Try
con.Open()
'Accessing methods to obtain schema information
dt = con.GetOleDbSchemaTable(OleDb.OleDbSchemaGuid.Tables, New Object() _
{Nothing, Nothing, Nothing, "TABLE"})
'loop datatable to store schema information within it
For i = 0 To dt.Rows.Count - 1
'compile lbtables with a list of available tables from the database
frmAddTable.lbTables.Items.Add(dt.Rows(i)!TABLE_NAME.ToString())
Next
Catch ex As Exception
MessageBox.Show(ex.Message.ToString(), "Data Load Error", MessageBoxButtons.OK,
MessageBoxIcon.Exclamation)
End Try
con.Close()
As you can see, at the very top is all the information regarding the connection to the database and loading of the information into the dataset.
My question is this; Whenever I need to gain access to the database and any information within it, will I have to perform all the connection process (oledbconnection, etc..)
or is there I way I can create a class for the connection functions and simply reference them whenever I need to connect?
For example, I now am in the process of creating another sub which gathers the columns, based on the tables chosen in the listbox, and displays it back onto the main form in the relevant checklistbox, again, connecting to the database, therefore would I need to perform all of the connection processes?
Any information would be very useful, thank you!

It is a standard approach to separate your DAL ( Data Access Logic ) from your Business Logic. I would definitely create a separate class for connecting to the database and executing the queries that would bring back the results that you can then either Bind to a control or iterate over inside a loop.
You might even want to look into using EF ( Entity Framework ) or my favorite LINQ to SQL to help in following a standard Design Pattern. By using a framework like EF or L2S you can leverage their ability to cache objects and return back strongly typed objects versus loosely typed. Strongly typed objects give you intelisense and are less prone to common mistakes like misspelling a field from a DataTable.

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.

How to use binary search in Visual Basic to search a Microsoft Access Database

I'm creating a program in Visual Basic for a school project. The program is a very simple tool to aid in the designing of a guitar. Users must login to use the program. I have setup an Access database to store all the data on the users and their designs. At the moment the login system uses SQL queries to find the inputted username in the database:
Private Sub cmd_login_Click(sender As Object, e As EventArgs) Handles cmd_login.Click
Call Login_Validation()
provider = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source ="
'access database location
dataFile = "C:\Users\Jackson\Desktop\Guitar Builder\Guitar Builder.accdb"
connString = provider & dataFile
myConnection.ConnectionString = connString
'the query:
myConnection.Open()
Dim cmd As OleDbCommand = New OleDbCommand("SELECT * FROM [Users] WHERE [Username] = '" & usn_box_login.Text & "' AND [Password] = '" & psw_box_login.Text & "'", myConnection)
Dim dr As OleDbDataReader = cmd.ExecuteReader
' userExists is set to true if the username user is found or false if it is not found
Dim userExists As Boolean = False
'if found:
While dr.Read
userExists = True
FullName = dr("Full Name").ToString
userName = dr("Username").ToString
End While
'checking the result
If userExists = True Then
Me.Hide()
Dashboard.Show()
Dashboard.lbl_name.Text = FullName
Dashboard.lbl_username.Text = userName
Else
MsgBox("Sorry, username or password not found", MsgBoxStyle.OkOnly, "Invalid Login")
End If
usn_box_login.Clear()
psw_box_login.Clear()
myConnection.Close()
End Sub
This works, however there must be a binary search in the program for it to pass the school's assessment. What is the easiest way to implement binary search to find the username?
Thank you in advance.
You can't. One of the advantages of using a DBMS like Access (or SQL Server, or SQLite, etc) is to abstract away the details of how data is retrieved and looked-up.
(Most modern database systems use special index structures for quick lookup, such as B-trees (B-trees are not Binary-search trees btw)
If the requirement is to use binary-search to find something, you need to not use something that will do it for you.
As this is for a programming exercise to demonstrate a working knowledge of data structures, I think you should remove Access completely and store data in a simple flat-file, load it all into memory when your program starts, then use your algorithms and structures to work with the data, before spitting it out to the flat-file store when your user clicks the Save button.
Note that I'm guessing using .NET's Array.BinarySearch is also probably cheating.
Other tips:
Don't store passwords in plain-text. They should not be encrypted either. Instead they should be hashed (and preferably salted).
Don't generate SQL using string concatenation. Use parameters instead. (Your code is vulnerable to SQL injection: if you put the text Baba O'Reilly in your textboxes your program will crash.
You should dispose of all your IDisposable objects correctly, ideally using a Using statement.
Run FxCop (Visual Studio Code Analysis) as part of your build process to catch other issues. Choose the "All Rules" setting.
The above bullet-points might sound like nit-picking, but I believe it's important to get into good habits early. The last thing an employer needs is a new hire who added significant vulnerabilities just because they never got used to doing things correctly.
I have taken your advice and removed Microsoft Access completely. I am now using my own record structure within the program.

VB.net Disconnected Table

I'm trying to load configuration settings into a set of DataTables and then disconnect from the database. I'm sure I am doing something wrong as the DataTables are empty afterwards. Here is the code:
From the top of the class:
'Set up Configuration DataTables
Dim dtDataAlerts As New DataTable
Running the Routine to get the data:
Public Sub ReadDataAlerts()
'Read the configuration for the Data Alerts from the RDB
dtDataAlerts = GetRecordSet("SELECT DataAlertGroups.DataAlertGroup_UID, DataAlertGroups.EmailGroup_UID, DataAlertGroups.EmailTemplate_UID, EmailTemplates.EmailTemplate_CustomSubject, EmailTemplates.EmailTemplate_CustomMessage FROM (DataAlertGroups INNER JOIN EmailGroups ON DataAlertGroups.EmailGroup_UID=EmailGroups.EmailGroup_UID) INNER JOIN EmailTemplates ON DataAlertGroups.EmailTemplate_UID=EmailTemplates.EmailTemplate_UID")
End Sub
The routine to get the DataTable
Function GetRecordSet(SQLString As String) As DataTable
'function used to run a query and return a disconnected DataTable
Try
'Create Dataset, Open Connection
Dim dsPWC As New DataSet()
Dim OleDbDataAdapter1 As System.Data.OleDb.OleDbDataAdapter = New System.Data.OleDb.OleDbDataAdapter(SQLString, sqlConn)
sqlConn.Open()
'Fill the Dataset with the PlantWatchConfiguration Table
OleDbDataAdapter1.Fill(dsPWC, "CollectorAlertGroups")
'Create Table from Dataset and iterate data
Dim DT As New DataTable
Dim DTClone As New DataTable
DT = dsPWC.Tables(0)
DTClone = DT.Clone
'Close Connection
sqlConn.Close()
Return DTClone
Catch ex As Exception
WriteToLog(ex.Message, "GetRecordSet")
End Try
End Function
I know the SQL is correct as I have already run it against the RDB and it produces results. I have a ton of logging to file in my code, so I am sure the database is connecting properly. (And other direct queries pull back data just fine)
But I am doing something wrong on the GetRecordSet function. I'm thinking that I am not properly cloning and disconnecting?
Anyway... I'm sure this is simple since I am not a coding expert :)
Thanks.
The error is exactly the Clone method. It clones the datatable structure, not the data.
DataTable.Clone: Clones the structure of the DataTable, including all DataTable schemas
and constraints.
If you want the data you need to use the Copy method.
DataTable.Copy: Copies both the structure and data for this DataTable.
However, as I have said in my comment, you don't need to waste the memory of your PC in this way.
ADO.NET is based on the disconnected model. The datatables present in the Dataset filled by the adapter are already disconnected from the database and you could return directly the table at index zero without any useless copy/clone.

how to query/get data from Datasource in VB.NET

i am building a database application in vb.net and i started by adding a data source from the DATA in the toolbar. my connection is good and it shows all my tables in the data source panel.
i also see new classes related to my database, like
sakilaDataSet
sakilaDataSet.customerDataTable
...
and so on.
how do i query and use these ? i googled a lot and i am not able to get this.
Dim cust As sakilaDataSet.customerDataTable = New sakilaDataSet.customerDataTable
Dim row() As System.Data.DataRow = cust.Select("customer_id=5")
MsgBox(row.Count)
My last try was with the above code, but the row.count always turns out to be zero.
You need to open a connextion to the DB. Here are some options:
You could use EntityFramework, which provides a nice way to access data and control it by mapping to entities (classes). For this, in VisualStudio create a ClassLibrary project, add an item ADO.NET Entity Data Model. This will open a wizard that will help you connect to the DB, map the objects in the DB to entities and access the entities by a reference to an entity context. The basics are easy.
Other option is to use an OLEDB provider, which is a classic way to access DB. An example to open an Access DB of employees:
Dim connString As String = "provider= microsoft.jet.oledb.4.0; " & _
"data source=Employee.mdb;"
Dim conn As New OleDbConnection(connString)
Try
conn.Open()
Finally
conn.Close()
Console.WriteLine("Connection Closed")
End Try
Visit http://www.connectionstrings.com/ to get a list of common connection string for many DB. Other useful links:
EntityFramework:
http://www.codeguru.com/csharp/csharp/net30/article.php/c15489
http://www.asp.net/entity-framework/tutorials
OLEDB:
http://oreilly.com/catalog/progvbdotnet/chapter/ch08.html
http://www.homeandlearn.co.uk/net/nets12p2ed.html
http://www.sourcecodester.com/tutorials/net/database-programming-made-easy.html
Hope this helps.
What i wanted to achieve was not to use connection strings again. After adding the data source in VB.net, it makes Data Classes and Adapters, which i can use directly to access the database, as follows :
Dim staff As sakilaDataSet.customerDataTable = New sakilaDataSetTableAdapters.customerTableAdapter().GetData
Dim rows() As sakilaDataSet.customerRow = staff.Select("email='" + email.Text + "'")
This website http://visualbasic.about.com/od/usingvbnet/a/begdbapp7.htm had a good tutorial where it talked about what happens when you use the data sources window and how to use it in your code after that.
I know it's an old question, but it was very high in Google results, and it was more of a "This is how you should have done it" answer instead of actually answering with what it seems like you asked

Using TableAdapter to insert rows into a dataset does not do anything

I have a question similar to this one, but reading the (accepted) answer didn't give me much insight, so I'm hoping to state it more clearly and get a clearer response back.
I'm attempting to insert a data row into a table. I'm using TableAdapter's custom "insert nonQuery" that I wrote (it works, I tested) to accept some parameters. I'm fairly new to this business of communication with a database via .NET and what I'm doing is probably wrong by design. My questions are why is it wrong and what's the right way to do it? Both are equally important, IMO.
Here's some sample VB code I wrote:
Dim arraysTableAdapter As New UnitTestsDataSetTableAdapters.ArraysTableAdapter
Try
arraysTableAdapter.InsertArray("Test Array", 2, 1, 2, "Test user")
Catch ex As SqlException
MsgBox("Error occured when trying to add new array." _
& vbNewLine & vbNewLine _
& ex.Message)
End Try
...and that's pretty much it. There is no exception raised, my table does not get a new row inserted. Everything is just the way it was before I called the InsertArray method. When I test my query in the QueryBuilder with the same parameters, a new row gets added to the database.
Now, I do understand some of the reasons this would not work. I understand that I need to create and select a row in my DataSet (no idea how to do it) in order to tell the TableAdapter what it's adding the data to. Or at least I got that impression from reading the vast abyss of forums.
I would really like to use TableAdapter at some point, because it knows that .InsertArray exists and it knows which parameters it likes. I could try and do it using
Dim con As New SqlConnection
Dim cmd As New SqlCommand
con.ConnectionString = connString
con.Open()
cmd.CommandText = "INSERT ...... all that jazz"
but it's not nearly clean enough for how clean I like my code to be. So, is there any way to do what I'm trying to do the way I'm doing it? In other words, how do I use the neat structure of a TableAdapter to communicate to my DataSet and put a new row in it?
Thanks in advance!
There were two things that were wrong:
(minor issue) I did not have a DataTable filled from the TableAdapter (see code below)
(major, sneaky issue) My method worked from the very beginning. There is nothing extra to be added except for the line above. However, the ConnectionString of arraysTableAdapter was pointing my program (automatically, by default) to a wrong location. Once I manually set the ConnectionString, it worked perfectly.
Here's my complete code:
Dim connString As String = "Some correct connection string"
Dim arraysDataTable As New SpeakerTestsDataSet.ArraysDataTable
Dim arraysTableAdapter As New UnitTestsDataSetTableAdapters.ArraysTableAdapter
'Set the correct connection string'
arraysTableAdapter.Connection.ConnectionString = conn
'Fill table from the adapter'
arraysTableAdapter.Fill(arraysDataTable)
Try
arraysTableAdapter.Insert("Test", 2, 1, 2, Now, Now, "Me")
Catch ex As Exception
MsgBox("Error occured when trying to add new array." _
& vbNewLine & vbNewLine _
& ex.Message)
End Try
The accepted answer in the question you linked to is correct, but sometimes saying it in different words helps:
A TableAdapter is used to communicate between a DataTable (there can be one or more DataTables in a DataSet) and a database. It can pull data from a database and add it to a DataTable and it can send data from a DataTable to the database. It's purpose is to create and execute the SQL code required to make this communication work.
You are trying to use the TableAdapter to directly add data to your DataTable. This will not work. Instead, you should use the methods that come with the DataTable to add a new row to the DataTable and then (if necessary) use your TableAdapter to send that row to a database.
For instance, with a Dataset called DataSet1 that contains a DataTable called DataTable1 that has three text columns you can add a record like this:
Dim d As New DataSet1
d.DataTable1.AddDataTable1Row("value1", "value2", "value3")
That AddDataTable1Row method is automatically created for you, and I think is what you are looking for.