Recordsets in VB.NET - vb.net

All,
Trying to implement a recordset approach in VB.NET and (with the wonderful help of this community) have gotten to the point where things almost run. :)
Code:
Dim strSQL As String
Dim rsMaster As New ADODB.Recordset
strSQL = "select * " & "from tblDQ " & "order by xid, xcode, xDOS"
rsMaster.Open(strSQL, objConn, adOpenForwardOnly, adLockOptimistic)
The last line throws an exception while attempting to execute the rsMaster.Open line:
COM Exception was unhandled
Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another.
Any ideas? Changing the cursor type or lock type doesn't seem to do any good, and the types specified above are available as options when coding the line. I've (on a WAG) added the following lines to the project:
Imports ADODB.LockTypeEnum
Imports ADODB.CursorTypeEnum
with no luck.
TIA!
Dave

Some ideas:
Does the SQL statement work in a "pure" database tool? (The &s looks a bit strange, but I assume that's a formatting issue in SO.)
The select * should work, but try a specific simple column (a short string or an integer), maybe there is an issue with a "tricky" column data type.
Do you have the objConn declared and a proper connection opened?
Some more ideas:
As you get the error when you execute the statement it seems that there is a problem with your statement. Is there a really simple SQL statement that will work in your scenario? (no order by, just a column, ..)
Try the statement from within MSAccess using the same connection parameters you are using in your VB.NET program. Maybe you are using a different user from within your program, maybe you have to qualify the table name etc.
If you say the connection is working fine, what did you do using the connection? Was there anything requiring access to the DB?

Ok, if removing the adOpenForwardOnly and the adLockOptimistic parameters doesn't change anything, how about changing the code slightly to use the Execute Method of the Connection object?
rsMaster.Open(strSQL, objConn, adOpenForwardOnly, adLockOptimistic)
Becomes
rsMaster = objConn.Execute(strSQL)

Not sure about your connection. You have an Access tag, but mentioned you tested in SQL Server. If you are using an access .mdb file
Imports adodb
Public Class Form1
Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim strSQL, strConn As String
Dim rsMaster As New ADODB.Recordset
Dim objConn As New ADODB.Connection
strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\DQ\DQ.mdb"
objConn.Open(strConn)
strSQL = "select * " & "from tblDQ " & "order by xid, xcode, xDOS"
rsMaster.Open(strSQL, objConn, CursorTypeEnum.adOpenForwardOnly, LockTypeEnum.adLockOptimistic)
rsMaster.MoveFirst()
Me.Text = rsMaster("xcode").Value
rsMaster.Close()
rsMaster = Nothing
End Sub
End Class

Related

How do I fetch data from Access database records and display/save them as textboxes/variables in VB.net?

coding noob here. I'm looking for help after hours of googling and watching YouTube tutorials provided no success. I've also tried looking at many of the posts on this website. I keep running into the same problem.
In Visual Studio I am attempting to create a solution with VB.net, it is currently successfully linked to an Access Database with which I can view, add, edit, and save records live.
I am trying to fetch data from the Access database based on a search of one of the fields, and then save that data as a variable.
(Code shown below)
Upon attempting to click the search button, I received the following exception: System.Data.OleDb.OleDbException: 'Syntax error (missing operator) in query expression 'First Name'.'
I believe it is because my field names are two words, but I have no idea how to fix this. Just typing it with one word gives this exception instead:
System.Data.OleDb.OleDbException: 'No value given for one or more required parameters.'
I have been completely unable to make progress despite watching multiple different versions of tutorials on how to perform this. Could someone please help me out?
Here is the code:
Public Class FormTraits
Private Sub FormTraits_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Sub FNButton_Click(sender As Object, e As EventArgs) Handles FNButton.Click
Dim conn As New OleDbConnection
conn.ConnectionString = ("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\Access Database.accdb")
conn.Open()
Dim strsql As String
strsql = "select ID, First Name, Last Name from PlayerData where First Name=" + TextBoxSearch.Text + ""
Dim cmd As New OleDbCommand(strsql, conn)
Dim myreader As OleDbDataReader
myreader = cmd.ExecuteReader
myreader.Read()
TextBoxFirstName.Text = myreader("First Name")
TextBoxLastName.Text = myreader("Last Name")
TextBoxID.Text = myreader("ID")
conn.Close()
End Sub
End Class
You should avoid using names including spaces or other special characters for tables, columns, etc, in your database. Just as you would do for a variable name or the like in VB - and as you have done for your table name - you should name your columns FirstName and LastName. If you must include spaces or other special characters, you must escape the identifiers in your SQL code. You also need to wrap text literals in single quotes, much as you wrap them in double quotes in VB:
strsql = "SELECT ID, [First Name], [Last Name] FROM PlayerData WHERE [First Name] = '" & TextBoxSearch.Text & "'"
It would be better if you used parameters instead of string concatenation, but that's beyond the scope of this question.

Excel VBA Late Bind to Access and SQL Insert

I am having a frustrating issue with late binding to MS Access from Excel VBA to execute a DML statement like Insert or Update. All of the data I use in vba comes from user defined Classes. I can query just fine but writing to the DB gets different errors each time I try a different way to do the same thing. Below are some links to the same/similar issues, however each is slightly out of context and therefore I could not get passed my problem.
Microsoft.ACE.OLEDB.12.0 Current Recordset does not support updating error received when trying to update access
Operation must use an Updateable Query / SQL - VBA
Update an excel sheet using VBA/ADO
Operation must use an updatable query. (Error 3073) Microsoft Access
https://msdn.microsoft.com/en-us/library/bb220954%28v=office.12%29.aspx?f=255&MSPPError=-2147217396
http://www.access-programmers.co.uk/forums/showthread.php?t=225063
My end goal is to simply execute a DML string statement and it has to use late binding. Mainly I get the 3251 error saying my connection is 'Read Only' or a missing ISAM when I add ReadOnly=0 to the connection string. Fyi, getProjectFile just returns a path to a file starting from the parent folder of my project. I am pretty sure I can just use the connDB.Execute so I only need SQL Insert, I don't want to query first because the queries will get fat quick. I also think something might be wrong with the enum params because the ExecuteOptions want bitmasks instead of just a Long and I don't really know how to do that. From most of my research, I kept getting referred to the LockType and/or cursor not being right. For my environment; Windows 8.1 64bit, MS Office 2010 32bit(required). Does anyone see what is wrong here?
Sub ADO_Tester()
Dim strSQL, strFile, strConnection As String
Dim connDB As Object
'late bind to the ADODB library and get a connection object
Set connDB = CreateObject("ADODB.Connection")
'Connect to the DB
strFile = Application.ActiveWorkbook.Path & "\" & "PortfolioDB.accdb"
strConnection = "Provider = Microsoft.ACE.OLEDB.12.0; data source=" & strFile & ";"
connDB.Open strConnection
'insert statement for a test record
strSQL = "INSERT INTO underlying_symbol (symbol) VALUES ('xyz')"
'execute the
connDB.Execute strSQL, , 2, 1 + 128
'clear the object
connDB.Close
Set connDB = Nothing
End Sub
Edit:
Early binding:
connDB.Execute strSQL, , adCmdText + adExecuteNoRecords
Late Binding: How to enter the value for adExecuteNoRecords? On msdn it is 0x80 and another post says &H0001,either way it gives a syntax error. It says enter a bitmask for this enum value.
connDB.Execute strSQL, , 1 + 0x80
Edit: Now the correct way -
adExecuteNoRecords (the ADO enum value) = 0x80 (a binary value) = 128 (a decimal value)
connDB.Execute strSQL, , 1 + 128
Edit: Now the issue gets even deeper. When I execute the code in a test spreadsheet into a test database, it works. When I copy and paste into the actual project spreadsheet and point to actual project db, I get the error: operation must use an updateable query . . . again. Same db name, same dml, same table name. The only difference is the actual DB is a product of a split to separate it from the forms and code in Access. Could this have changed some setting to make it read only?
Edit: It just gets deeper and deeper. The issue causing it not to work in the project db is because I have some Excel Tables querying the db. I made these through the Excel UI, Ribbon -> External Data -> Access -> etc. . . It has now become obvious these are causing me to be unable to insert DML because they are probably set to read only. How can I change the tables connections permissions? Is there another way I could be making these tables so that I can provide the connection? How to get Tables to be friendly with DML in VBA?
This worked for me:
Option Explicit
Private Const acCmdText As Integer = 1
Sub ADO_Tester()
On Error GoTo ErrorHandler
Dim strSQL As String
Dim strFile As String
'Dim adoRecSet As Object
Dim connDB As Object
'late bind to the ADODB library and get a connection object
Set connDB = CreateObject("ADODB.Connection")
'Connect to the DB
strFile = getProjectFile("core", "PortfolioDB.accdb")
connDB.Open connectionString:="Provider = Microsoft.ACE.OLEDB.12.0; data source=" & strFile & ";"
'If State = 1, db connection is okay.
MsgBox "ADO Connection State is " & connDB.State & "."
'SQL to get the whole [underlying_symbol] table
'strSQL = "underlying_symbol" 'if options 2
'strSQL = "SELECT * FROM underlying_symbol" 'if options 1
strSQL = "INSERT INTO underlying_symbol (symbol) VALUES ('xyz')"
'late bind to adodb and get recordset object
'Set adoRecSet = CreateObject("ADODB.Recordset")
'&H0001 = bitmask for aCmdText
connDB.Execute strSQL, , acCmdText
'With adoRecSet
' .Open Source:=strSQL, _
' ActiveConnection:=connDB, _
' CursorType:=1, _
' LockType:=3, _
' Options:=&H1
'.AddNew
'.fields("symbol") = "XYZ"
'.Update
'End With
'------------------
'close the objects
'adoRecSet.Close
connDB.Close
'destroy the variables
'Set adoRecSet = Nothing
Set connDB = Nothing
ExitMe:
Exit Sub
ErrorHandler:
MsgBox Err.Number & ": " & Err.Description
GoTo ExitMe
End Sub
Added some error handling, a constant that defines acCmdText (Why just not add a reference to ADO library? Up to you, though.), and a message box to check the connection state to the database, as I can't test your getProjectFile function. Late binding doesn't seem to be the issue here, I think the key line is:
connDB.Execute strSQL, , 2, &H1
Can really say what's going on here as I've never done it like this (code doesn't even compile), but changing it to
connDB.Execute strSQL, , acCmdText
worked for me.

SSCE - Multiple-Step OLE DB operation generated errors

I'm using a SQL Server Compact database (3.5). I have run through every article on this site (and others) I could find about this issue, but can't seem to find the problem. I am using Visual Studio 2012, VB.Net.
My provider string is:
Dim sqlConn As New System.Data.OleDb.OleDbConnection("Provider=Microsoft.SQLServer.CE.OLEDB.3.5;Data Source=" & My.Application.Info.DirectoryPath & "\pw.sdf" & ";Password=XXXyyy1234;Persist Security Info=True;")
My code where it all breaks down is:
'Create SQL Query
Dim SQLString As String = "SELECT * FROM EmailGroups"
'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()
And, of course, it breaks down on .Open().
I picked selecting from that datatable because it is a simple one.
EmailGroup_UID [int][PK]
EmailGroup_Name [nvarchar][length=50]
I'm sure I've been simply staring at this too long and can't see the forest for the trees anymore, so I'm hoping someone can slap me straight :)
Thanks in advance.
EDIT: This code all works when tying to the original MS Access 2007 database (accdb). Different provider, of course. And - I didn't import the tables, I re-created manually.
2nd EDIT: Immediate Window says 'A first chance exception of type 'System.Data.OleDb.OleDbException' occurred in System.Data.dll'
You should use SqlCeConnection instead of OldDbConnection.
if you must use OleDbConnection, use "ssce:database password" like so:
"Provider=Microsoft.SQLServer.CE.OLEDB.3.5;Data Source=" & My.Application.Info.DirectoryPath & "\pw.sdf" & ";SSCE:Database Password=XXXyyy1234;Persist Security Info=True;"

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 & "'"

What's the best way to read a very large database table in VB.NET?

I'm developing a VB.NET application to obtain data from any data source (using an odbc connection string), and because this I can't use specific .net connectors like MySql.Net connector and I can't previously know if the file/DMBS supports LIMIT parameter. This app will read data from a table in the data source and use the information to make some files. At this point there was no problem with some tables because they are less than 3,000,000 records length, but there is a table that has 5,000,000+ rows length, and when I send the query the connection is lost. I'm working with OdbcDataReader, because I read on MSDN site that this is the best way to read a table one row at time and I just use each record once.
This is an example of my code:
Private Sub ReadData()
dim cnn as odbc.odbcConnection
dim coma as odbc.odbcCommand
dim reg as odbc.odbcDataReader
try
cnn=new odbc.odbcConnection("Driver={MySQL ODBC 3.51 Driver}; server=localhost; Database=datos; User=usuario; Password=contrasenia; option=3;")
cnn.open()
coma=new odbc.odbcCommand("select * from tabla")
reg=coma.ExecuteReader()'<- when this line is executed fails with the 5,000,000+ length table.
catch ex as Exception
MessageBox("Error: "+ex.Message,MsgBoxStyle.Critical,"Error")
end try
... 'Do anything with the data
end sub
In VBA or VB6 I do something like this:
Private Sub ReadData()
dim cnn as object
dim tab as object
set cnn = CreateObject("ADODB.Connection")
set tab = CreateObject("ADODB.Recordset")
cnn.cursorlocation=3
cnn.open "Driver={MySQL ODBC 3.51 Driver}; server=localhost; Database=datos; User=usuario; Password=contrasenia; option=3;"
tab.open "tabla", cnn,,2
...'Do anything with the data
end sub
And this code is executed without problem.
Any idea how to retreive data in a more efficent way in VB.NET? Or there is any way to do like ADODB (just indicating the table name not the SQL sentence).
Sorry if anything is incomprehensible.
Perhaps try setting the ConnectionTimeout property? Try adding this line before your cnn.open() call:
cnn.ConnectionTimeout = 50000 ' Number of seconds before timeout
When I had similar problem, my solution was to add LimitQuery function that added keywords to query to limit the number of results depending on the provider.
Something like this:
Public Function LimitQuery(ByVal query As String, ByVal RowLimit As Integer) As String
If RowLimit > 0 Then
Select Case m_DbType
Case DbType.Oracle
return "SELECT * FROM(" & query & ") WHERE ROWNUM<" & cstr(RowLimit + 1)
Case DbType.SQLServer
return Replace(query, "SELECT", "SELECT TOP " & cstr(RowLimit), 1, 1)
Case DbType.MySQL
return query & " LIMIT " & cstr(RowLimit)
End Select
Else
return query
End If
End Function
This is jast a quick hack, if you want to use any data source, sooner or later, you'll need some database abstraction layer.