VB.net Update MS Access from DataGridView with BindingSource - sql

I have a DataGridView populated with a SQL statement that users can input data on certain columns:
Me.bndDataGrid.DataSource = GetData("SELECT H.InnCode, R.RSRM, " & strCols & " E.Escalation " & _
"FROM (((dbo_HotelInfo AS H " & _
"INNER JOIN dbo_RSRM AS R ON H.RevMgr = R.ID) " & _
"INNER JOIN dbo_SrMgr AS S ON R.SrMgr = S.ID) " & _
"INNER JOIN " & strHitList & " AS L ON H.FacilityID = L.FacilityID) " & _
"INNER JOIN dbo_Escalation AS E ON H.FacilityID = E.FacilityID " & _
"WHERE S.ID = " & cbxSrMgr.SelectedValue.ToString)
With Me.grdQueryResults
.AutoGenerateColumns = True
.DataSource = bndDataGrid
End With
bndDataGrid is the BindingSource for grdQueryResults, the DataGridView. The code for GetData is commonly found on MS forums:
Private Shared Function GetData(ByVal sqlCommand As String) As DataTable
Dim strConn As String = "Provider=Microsoft.ACE.OLEDB.12.0; Data Source={MS Access DB Path Here};"
Dim ctnHitList As OleDbConnection = New OleDbConnection(strConn)
Dim tblHitList As New DataTable
Dim cmdHitList As New OleDbCommand(sqlCommand, ctnHitList)
Dim adrHitList As OleDbDataAdapter = New OleDbDataAdapter()
adrHitList.SelectCommand = cmdHitList
tblHitList.Locale = System.Globalization.CultureInfo.InvariantCulture
adrHitList.Fill(tblHitList)
Return tblHitList
End Function
Now once users are ready to save changes I can't for the life of me figure out how to have this save correctly, mostly since the data source for the DataGridView isn't simply bound to a table.
EDIT:
OK, so I mostly overhauled my code in accordance with Crowcoder's blog page, and got a lot further with it, but now on updating I'm running into a "Concurrency violation: the UpdateCommand affected 0 of the expected 1 records" exception. Here's the update code:
Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
Dim parInnCode As OleDbParameter = New OleDbParameter("#parInnCode", OleDbType.WChar)
Dim parNotes As OleDbParameter = New OleDbParameter("#parNotes", OleDbType.WChar)
parInnCode.SourceColumn = "InnCode"
parNotes.SourceColumn = "Notes"
Using ctnDataGrid As New OleDbConnection(getConnectionString())
Using cmdGrid As New OleDbCommand("UPDATE (dbo_The400 AS T INNER JOIN dbo_HotelInfo AS H ON T.FacilityID = H.FacilityID) " & _
"INNER JOIN dbo_RSRM AS R ON H.RevMgr = R.ID " & _
"SET [Notes] = #parNotes WHERE H.InnCode = #parInnCode", ctnDataGrid)
Using adrDataGrid As New OleDbDataAdapter()
With adrDataGrid
.UpdateCommand = cmdGrid
With .UpdateCommand.Parameters()
.Add(parInnCode)
.Add(parNotes)
End With
grdQueryResults.EndEdit()
.Update(tblDataGrid)
End With
End Using
End Using
End Using
End Sub
tblDataGrid is declared at the Form Class level, wondering if that may be the issue or if my update query doesn't match the number of columns in the table? Or something else? Can't seem to find the right answer for my case :/

Welp, at long last I figured it out. It involved quite a bit of back end reorganizing to make it easier to connect to it via the front end .net application. Basically I threw all manager inputs into one table and added a column that corresponds to the initiative that required their input.
From there, I could build just about everything in the Dataset Designer and set the Update command on that tableadapter to just update that one table. Cut down the code on the main form to just a few lines that fill the datasources for the combobox columns in the datagridview.
Not an elegant coding solution, but it works!

Related

SQL query is not running IN VB.NET

I am fresher in VB.NET and I am trying to execute an SQL query in VB.NET but not showing any value at output. Can u please help me to find where am I going Wrong.
Dim sConnectionString As String _
= "User ID=XXX ;Password=XXX;Initial Catalog=gemXXX;Data Source=SCRBAMSDKBXXXXXX"
Dim objConn As New SqlConnection(sConnectionString)
objConn.Open()
Dim sw ,readerObj
Dim sSQL As String = "select top 1 " & sw & " = e.import from tblrelcoms r , [beant].[dbo].tblequipments e where r.IDEquipment = e.IDEquipment"
Using readerObj As SqlClient.SqlDataReader = cmdObj.ExecuteReader
Dim objCmd As New SqlCommand(sSQL, objConn)
objCmd.ExecuteNonQuery()
TextBox1.Text = sw.ToString()
The problem you have is that you cannot just concatenate a variable into SQL and expect it to be updated once the SQL is executed.
ExecuteScalar is probably the easiest way of achieving what you want:
Dim sConnectionString As String _
= "User ID=XXX ;Password=XXX;Initial Catalog=gemXXX;Data Source=SCRBAMSDKBXXXXXX"
Dim sSQL as string = "SELECT TOP 1 e.import " _
"FROM tblrelcoms r " & _
" INNER JOIN [beant].[dbo].tblequipments e " & _
" ON r.IDEquipment = e.IDEquipment " & _
"ORDER BY e.Import;"
Using connection = new SqlConnection(sConnectionString)
Using command = New SqlCommand(sSQL, connection)
connection.Open()
TextBox1.Text = command.ExecuteScalar().ToString()
End Using
End Using
Although if you need more than one column, then you could use a data reader:
Dim sConnectionString As String _
= "User ID=XXX ;Password=XXX;Initial Catalog=gemXXX;Data Source=SCRBAMSDKBXXXXXX"
Dim sSQL as string = "SELECT TOP 1 e.import " _
"FROM tblrelcoms r " & _
" INNER JOIN [beant].[dbo].tblequipments e " & _
" ON r.IDEquipment = e.IDEquipment " & _
"ORDER BY e.Import;"
Using connection = new SqlConnection(sConnectionString)
Using command = New SqlCommand(sSQL, connection)
connection.Open()
Using reader = command.ExecuteReader()
If reader.Read()
TextBox1.Text = reader.GetString(0)
End If
End Using
End Using
End Using
I have made a couple of other changes too.
Added Using blocks to ensure IDisposable objects are disposed of properly.
Updated the sql join syntax from ANSI 89 implicit joins to ANSI 92 explicit joins, as the name suggests the syntax you are using is 24 years out of date. There are many reasons to start using the new syntax, which is nicely covered in this article: Bad habits to kick : using old-style JOINs
Added an ORDER BY clause to your sql. TOP 1 without order by will give you indeterminate results (unless you only have one record, in which case top 1 is redundant)
A more complex solution would be to use output parameters, which will work and seems more in line with what you were originally trying to achieve, but is overkill for this situation (in my opinion):
Dim sConnectionString As String _
= "User ID=XXX ;Password=XXX;Initial Catalog=gemXXX;Data Source=SCRBAMSDKBXXXXXX"
Dim sSQL as string = "SELECT TOP 1 #Output = e.import " _
"FROM tblrelcoms r " & _
" INNER JOIN [beant].[dbo].tblequipments e " & _
" ON r.IDEquipment = e.IDEquipment " & _
"ORDER BY e.Import;"
Using connection = new SqlConnection(sConnectionString)
Using command = New SqlCommand(sSQL, connection)
connection.Open()
Dim p As SqlParameter = command.Parameters.Add("#Output", SqlDbType.VarChar, 255)
p.Direction = ParameterDirection.InputOutput
command.ExecuteNonQuery();
TextBox1.Text = p.Value.ToString()
End Using
End Using
*Please excuse any syntax errors, I have not used VB.Net in years, and some c# quirks may be in the below, such as I can't remember if you just don't have to use parentheses for a parameterless method, or if you can't... Hopefully there is enough basic structure to get you started

how to call checkbox value from sql to display on form vb.net

am doing this but not working only apply in first record its working in insert and update
i stored in sql as true or false
Sub db_load()
On Error Resume Next
Dim pringdata As String = "SELECT custcode_" & _
",custname_" & _
",custname2_" & _
",phone_" & _
",mobile_" & _
",custadd_" & _
",date_" & _
",cutomerzone_ " & _
",check_ " & _
" FROM custInfo "
Dim sqlconload As New SqlConnection(sqlcon)
sqlconload.Open()
Dim da As New SqlDataAdapter(pringdata, sqlconload)
ds.Clear()
da.Fill(ds, "custInfo")
For i As Integer = ds.Tables(0).Rows.Count = 0 To -1
If ds.Tables(0).Rows(i).Item("check_") = "true" Then
checkActive.Checked = True
Else
checkActive.Checked = False
End If
Next
sqlconload.Close()
I gather you are referring to a specific customer since you're only setting a single checkbox? You'll need to modify your query to match that.
Next, examine how you're storing the "check" column. In most cases, converting to Bool will resolve it but you may have to special case it based on available values.
Also, if the field you're looking at could be null, you'll have to account for that as well.
Here's a good pattern to follow that properly disposes of resources such as connections, commands, and readers.
Public Sub db_load()
Using cn = New SqlConnection(sqlcon)
cn.Open()
Using cmd = New SqlCommand("SELECT custcode,custname,custname2,phone,mobile,custadddate,customerzone,check FROM custInfo", cn)
Using dr = cmd.ExecuteReader()
If dr.Read Then
checkActive.Checked = CBool(dr("check"))
End If
End Using
End Using
End Using
End Sub

How to Trigger Code with ComboBox Change Event

I have a created a database containing historical stock prices. On my form I have two comboboxes, ComboBox_Ticker and ComboBox_Date. When these comboboxes are filled I want to check the database and see if the respective data exists in the database. If it does I want to change the text of a label called Label_If_Present to "In Database".
My problem occurs with the change event. I want all of this to happen once I change the data in the textboxes. I have tried both the .TextChanged and .LostFocus events. The '.TextChanged' triggers the code to early and throws and error in my SQL command statement. The `.LostFocus' event doesn't do trigger my code at all.
Here is my current code:
Public databaseName As String = "G:\Programming\Nordeen Investing 3\NI3 Database.mdb"
Public con As New OleDb.OleDbConnection("PROVIDER=Microsoft.Jet.OLEDB.4.0;Data Source =" & databaseName)
Public tblName As String = "Historical_Stock_Prices"
Private Sub Change_Labels(ByVal sender As Object, ByVal e As EventArgs) Handles ComboBox_Ticker.TextChanged, ComboBox_Date.TextChanged
con.Close()
Dim dr As OleDbDataReader
con.Open()
If (File.Exists(databaseName)) Then
Dim restrictions(3) As String
restrictions(2) = tblName
Dim dbTbl As DataTable = con.GetSchema("Tables", restrictions)
If dbTbl.Rows.Count = 0 Then
Else
Dim cmd2 As New OleDb.OleDbCommand("SELECT * FROM " & tblName & " WHERE Ticker = '" & ComboBox_Ticker.Text & "' " & " AND Date1 = '" & ComboBox_Date.Text & "'", con)
dr = cmd2.ExecuteReader
If dr.Read() = 0 Then
'If record does not exist
Label_If_Present.Text = ""
Else
Label_If_Present.Text = "In Database"
End If
con.Close()
End If
Else
End If
End Sub
I have successfully implemented this concept on other forms within my project. This one is slightly different and I can't figure out why I can't get this one to work.
Handling the TextChanged event should work, however you need to set the DropDownStyle to DropDownList so that the Text property can only be a given value.
Then check to see that both comboboxes have values selected. Something like this should work:
If ComboBox_Ticker.Text <> "" AndAlso DateTime.TryParse(ComboBox_Date.Text, Nothing) Then

Binding Source Filter not working in DGV

I'm having a problem with the binding source on a DGV . The message is "DataMember Property 'nodes' cannot be found on the dataSource " The column count is 14 after setting the table to the datasource. The error occurs on the line nodesDataGridView.DataSource = bsNodes. If I break before the error and then hover on the ds it does show that table nodes is in the datasource. I've used code similiar to this to setup other DGV's and I don't see any difference in this one.
if I remove these statements, I don't get the error but of course it is not filtered):
nodesDataGridView.DataSource = bsNodes
bsNodes.Filter = "company_number = " & Globals.customer_id
I should probably mention that I added company_number after the grid was completed and working. It was setup for a single company code but now I'm having to add the requirement to support multiple companies in the database.
Any ideas?
Thanks,
Vic
' Setup objects for loading the summary grid
Dim sqlNodes As String = "Select *From nodes order by display_sequence"
Dim comm As MySqlCommand = New MySqlCommand(sqlNodes, m_cn1)
Dim daNodes As MySqlDataAdapter = New MySqlDataAdapter(comm)
Dim dsNodes As DataSet = New DataSet()
dim bsNodes As New BindingSource
Try
AddHandler ButtonSaveChanges.Click, AddressOf ButtonSaveChanges_Click
dsNodes.Clear()
daNodes.Fill(dsNodes, "nodes")
m_cn1.Close()
nodesDataGridView.DataSource = dsNodes
nodesDataGridView.DataMember = "nodes"
bsNodes.DataSource = dsNodes.Tables("nodes")
Debug.Print("nodes column count is " & nodesDataGridView.ColumnCount)
nodesDataGridView.DataSource = bsNodes
bsNodes.Filter = "company_number = " & Globals.customer_id
Catch ex As Exception
MessageBox.Show("Failed to load summary grid" & vbCrLf & vbCrLf & ex.ToString)
End Try
try to filter like this
bsNodes.Filter = "company_number = '" & Globals.customer_id.ToString() & "'"
EDIT:
bsNodes.DataSource = dsNodes.Tables("nodes")
nodesDataGridView.DataSource = bsNodes '<- you set dsNodes(Dataset) this should be the BindingSource not Dataset
nodesDataGridView.DataMember = "nodes"
Debug.Print("nodes column count is " & nodesDataGridView.ColumnCount)
'nodesDataGridView.DataSource = bsNodes
bsNodes.Filter = "company_number = '" & Globals.customer_id.ToString() & "'"

SqlDataReader getting rows when no data

This is incredibly urgent, I need to present this application in 3 and a half hours.
My application checks against a data source to see if a value exists in the database and changes values depending on whether or not the value in question was found.
The problem is that I've run the sql query with the value in question in SSMS and no rows were returned, and yet, my DataReader says it has rows.
This means that my application is reporting inaccurately.
Here's my code:
Using conn As New SqlConnection("Data Source=.\SQLEXPRESS; Initial Catalog=Testing; Integrated Security=True;")
Dim cmd As New SqlCommand(sql, conn)
conn.Open()
Dim reader As SqlDataReader = cmd.ExecuteReader
If reader.HasRows Then
Value = True
AcctNumber = reader(1)
End If
reader.Close()
End Using
I've removed code that's not relevant to this post, but what you may want to know is:
Value is Boolean
AcctNumber is a String
As this is an application for work, I'd rather not include the SQL Query. The problem is the reader. If I comment out Value = True, I get the right info, but leaving that out will mean that in a case where Value should be True, it'll report inaccurately as well.
Thanks in advance!
EDIT: Full Source Code:
Case "Business"
' Change the number format to local because that's what it is in the db
If Microsoft.VisualBasic.Left(NumberToCheck, 2) = "27" Then
NumberToCheck = NumberToCheck.Replace(Microsoft.VisualBasic.Left(NumberToCheck, 2), "0")
End If
Dim sql As String = "SELECT a.TelNumber, c.AccountNumber " & _
"FROM TelInfo a " & _
"INNER JOIN Customers b ON a.CustID = b.pkguidId " & _
"INNER JOIN Accounts c ON b.pkguidId = c.CustID " & _
"WHERE a.TelNumber = '" & NumberToCheck & "'"
Using conn As New SqlConnection("Data Source=.\SQLEXPRESS; Initial Catalog=Testing; Persist Security Info=True; " & _
"User Id=JoeSoap; Password=paoseoj;")
Dim cmd As New SqlCommand(sql, conn)
conn.Open()
Dim reader As SqlDataReader = cmd.ExecuteReader
If reader.Read Then
Value = True
AcctNumber = reader(1)
End If
reader.Close()
End Using
On the comments below made before 08/02/10 (mm/dd/yy):
Value is just a boolean that gets returned by the function to indicate that the searched telephone number (NumberToCheck) exists in the database.
So...
Private AcctNumber As String
Dim val As Boolean = False
val = CheckNumber("3235553469")
If val Then
' AcctNumber will have been set by CheckNumber
Label1.Text = AcctNumber
End If
val will only be returned True if the NumberToCheck (in this example 3235553469) exists in the database.
Having copied the value of NumberToCheck into SSMS and testing the query there, I can verify that the query does work as expected.
No, I can't populate a DataSet because of the volume of information in the table (+/- 9.5m rows). Even with the 'WHERE' filter, the query is too heavy on resources and eventually ends in an OutOfMemory Exception which is why I went with a DataReader.
I'm going to try the ExecuteScalar option as suggested as an answer by Darryl now, will update with the results.
Try changing your If statement to
If reader.Read() Then
Value = True
AcctNumber = reader(1)
End If
HasRows exhibits strange behavior in certain situations, so it's better to avoid it altogether.
This does not solve the problem, but it may get you through your presentation. Use "ExecuteScalar" which should work when you return a single value.
AcctNumber = ""
AcctNumber = cmd.ExecuteScalar
If AcctNumber = "" Then
Value = False
Else
Value = True
End If
Just to be sure it's not a data problem, parameterize your SQL. Change the statement:
Dim sql As String = "SELECT a.TelNumber, c.AccountNumber " & _
"FROM TelInfo a " & _
"INNER JOIN Customers b ON a.CustID = b.pkguidId " & _
"INNER JOIN Accounts c ON b.pkguidId = c.CustID " & _
"WHERE a.TelNumber = #telNumber"
Then do this:
Dim cmd As New SqlCommand(sql, conn)
cmd.Parameters.AddWithValue("#telNumber", NumberToCheck) ' <==== added line
Edit
I think we're looking in the wrong place. Add this just before if reader.Read():
Value = false
AcctNumber = ""
This will make sure you're not having a variable-scope problem. (You are using Option Strict On, right?)
In the immortal words of Homer Simpson... "DOH!!"
I just had a look on the database that my application searches for the telephone numbers and, I don't know how I could have missed it, but the value I'm searching for is actually there.
The problem is, therefore, not likely anything to do with my code, but rather the data...