Error loading sql parameters in a loop, VB.Net - sql

I am currently working in Microsoft visual studio express 2013 with an sql back end. I am trying to run a loop through 2 comboboxes and a datetimepicker for any instance a checkbox is checked. However, I am running into an error that reads "System.ArgumentException: No Mapping exists from Object type system.windows.forms.datetimepicker to a known managed provider native type." When I run the code I have put a watch on the parameter value and it is not saving the data into the variable before the sql command fires. I think I need to store the variable in a different way to allow access to the variable. Here is my code:
Try
Using conn1 As New SqlConnection(connstring)
conn1.Open()
Using comm1 As New SqlCommand("SELECT isnull(max(AuditID) + 1, 1) as 'AuditID' FROM table1", conn1)
Dim reader1 As SqlDataReader = comm1.ExecuteReader
reader1.Read()
Dim AuditID As Integer = reader1("AuditID")
reader1.Dispose()
'Loop through all checkboxes and write into sql tables
Dim Run As Integer
For Run = 1 To 5
Dim LineItem = DirectCast(Me.Controls("CB" & Run), CheckBox)
If LineItem.Checked = True Then
Dim DateTime = DirectCast(Me.Controls("DTP" & Run), DateTimePicker)
Dim Frequency = DirectCast(Me.Controls("CBWeek" & Run), ComboBox)
Dim Repeat = DirectCast(Me.Controls("CBRepeat" & Run), ComboBox)
'sql statements
'select ID
Using conn2 As New SqlConnection(connstring)
conn2.Open()
Using comm2 As New SqlCommand("SELECT isnull(max(AuditID) + 1, 1) as 'ID' FROM table1", conn1)
Dim reader As SqlDataReader = comm2.ExecuteReader
reader.Read()
Dim ID As Integer = reader("ID")
reader.Dispose()
'Insert into table audit line
Using conn3 As New SqlConnection(connstring)
conn3.Open()
Using comm3 As New SqlCommand("INSERT INTO table1 (ID, AuditID, DateStart, Freq, repeats) " _
& "VALUES (#ID, #AuditID, #DateStart, #Freq, #Repeats)", conn3)
With comm3.Parameters
.AddWithValue("#ID", ID)
.AddWithValue("#AuditID", AuditID)
.AddWithValue("#DateStart", DateTime)
.AddWithValue("#Freq", Frequency)
.AddWithValue("#Repeats", Repeat)
End With
comm3.ExecuteNonQuery()
End Using
conn3.Close()
End Using
End Using
conn2.Close()
End Using
End If
Next
End Using
conn1.Close()
End Using
Catch ex As Exception
MsgBox(ex.ToString)
My try statement stop my code on this line:
comm3.ExecuteNonQuery()
However, I know that this error is coming from when I add my parameters, specifically these 3 lines:
.AddWithValue("#DateStart", DateTime)
.AddWithValue("#Freq", Frequency)
.AddWithValue("#Repeats", Repeat)
I am trying to get tese variables with a loop statement based on the design name here:
Dim DateTime = DirectCast(Me.Controls("DTP" & Run), DateTimePicker)
Dim Frequency = DirectCast(Me.Controls("CBWeek" & Run), ComboBox)
Dim Repeat = DirectCast(Me.Controls("CBRepeat" & Run), ComboBox)
It does not seem like the program likes using these dimensions above to be inserted into the sql table. Does anyone know a way I can carry these values over to the sql parameters statement?

There are a number of things I would do differently. First and always, use Option Strict, it will catch some of the type conversion you have going on.
I would get the controls from an explicit list rather then fetching from Controls. Just make a few arrays to hold the control refs so you do not need to to find them in the collection:
Private DTPs As DateTimePicker() = {DTP1, DTP2...}
This will avoid the need to cast them, fewer hoops and implied converts like "DTP" & Run:
Dim dt As DateTime ' vars for the SQL
Dim freq As Integer
For Run As Integer = 0 To 4
dt = DTPs(Run).Value
freq = cboFreq(Run).SelectedValue
...

I have fixed the problem, I needed to put my loop variables into .value type variables. I added this to fix it:
Dim DateTime = DirectCast(Me.Controls("DTP" & Run), DateTimePicker)
Dim Frequency = DirectCast(Me.Controls("CBWeek" & Run), ComboBox)
Dim Repeat = DirectCast(Me.Controls("CBRepeat" & Run), ComboBox)
Dim Time As Date = DateTime.Value
Dim Freq As Integer = Frequency.SelectedValue
Dim Again As Integer = Repeat.SelectedValue

Related

Having trouble getting the average for duration in (mm:ss)

For all who assist with this, thank you. My goal is to get the duration of chat conversations for my employees and then calculate their year average. The data is being inserted into a database as short text in the format of (mm:ss or 18:30). I have tried converting and parsing the data several different ways and I have looked through numerous explanations and solutions on SO.com so far with nothing working the way I would like. The below is my display procedure to bring the data into the form. I know I could have done this in an easier way, but I am fairly new to VB.net and coding in general.
Private Sub DisplayJanMetrics()
'Open a connection to the database and then assign the values from the appropriate metric columns to the appropriate labels.
Dim str As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\CoachingDB.accdb"
Dim conn As New OleDbConnection(str)
Try
conn.Open()
Dim sql As String = "SELECT Duration, CSAT, Away, Quality, Development FROM January WHERE Employee =" & "'" & cmbEmployee.SelectedItem.ToString & "'"
Dim cmd As New OleDbCommand(sql, conn)
Dim myReader As OleDbDataReader = cmd.ExecuteReader()
While myReader.Read
lblJanDuration.Text = myReader("Duration").ToString
lblJanCSAT.Text = myReader("CSAT").ToString
lblJanAway.Text = myReader("Away").ToString
lblJanQual.Text = myReader("Quality").ToString
lblJanDev.Text = myReader("Development").ToString
End While
Catch ex As OleDbException
MsgBox(ex.ToString)
Finally
conn.Close()
End Try
End Sub
Once the data has been loaded to the correct labels I have a button and click event to calculate the average from the labels - the other ones I was able to do easily because I could parse them to doubles and then do the calculation from there. Here is an image of what the form looks like, I think it will help all of you get an idea of what I am trying to accomplish.
This is what the form layout looks like
It is a good idea to separate your user interface code from your database code. You can use the same data retrieval function for any month by passing the month as TableName.
Database objects Connection, Command, and DataReader all need to be disposed and closed so they are placed in Using blocks. You don't want to hold the connection open while you update the user interface. Just return a DataTable and update the UI with that.
CalculateAverage first creates an array of the labels you want to include in the average. You can include all 12 but the average will not include empty labels. (IsNullOrEmpty)
Separate the string into minutes and seconds. Get the total seconds and add to the list.
Get the average number of seconds by calling Average on List(Of Integer).
Finally, turn the average seconds back into minutes and seconds and format a string to display.
Private Sub DisplayJanMetrics()
Dim dt As DataTable
Try
dt = GetEmployeeData(cmbEmployee.SelectedItem.ToString, "January")
Catch ex As Exception
MsgBox(ex.Message)
Exit Sub
End Try
If dt.Rows.Count > 0 Then
lblJanDuration.Text = dt(0)("Duration").ToString
lblJanCSAT.Text = dt(0)("CSAT").ToString
lblJanAway.Text = dt(0)("Away").ToString
lblJanQual.Text = dt(0)("Quality").ToString
lblJanDev.Text = dt(0)("Development").ToString
End If
End Sub
Private Function GetEmployeeData(Employee As String, TableName As String) As DataTable
Dim str As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\CoachingDB.accdb"
Dim sql As String = $"SELECT Duration, CSAT, Away, Quality, Development FROM {TableName} WHERE Employee = #Employee;"
Dim dt As New DataTable
Using conn As New OleDbConnection(str),
cmd As New OleDbCommand(sql, conn)
cmd.Parameters.Add("#Employee", OleDbType.VarChar).Value = Employee
conn.Open()
Using reader = cmd.ExecuteReader
dt.Load(reader)
End Using
End Using
Return dt
End Function
Private Function CalculateAverage() As String
Dim lst As New List(Of Integer)
Dim labels() = {Label1, Label2, Label3, Label4} 'an array of 1 thru 12
For Each label In labels
If Not String.IsNullOrEmpty(label.Text) Then
Dim fields = label.Text.Split(":"c)
Dim mins = CInt(fields(0))
Dim secs = CInt(fields(1))
lst.Add(mins * 60 + secs)
End If
Next
Dim avg = lst.Average
Dim avgMins = Math.Truncate(avg / 60)
Dim remainderSec = avg - avgMins * 60
Return $"{avgMins}:{remainderSec}"
End Function

Converting VBA function to VB.net to get sql data

I am trying to convert VBA code into VB.net and I have made it to a point but I can't convert resultset into vb.net. RS was 'dim as resultset' in VBA, thought i could just change it to dataset but am getting errors with the '.fields' and other options?
Function GetG(sDB As String, sServ As String, sJob As String) As String
'sDB = Database name, sServ = Server\Instance, path = job.path
Dim conString As String = ("driver={SQL Server};server = " &
TextBox1.Text & " ; uid = username;pwd=password:database = " &
TextBox2.Text)
Dim RS As DataSet
Dim conn As SqlConnection = New SqlConnection(conString)
Dim cmd As SqlCommand
conn.Open()
'This is where my problems are occuring
cmd = New SqlCommand("SELECT [ID],[Name] FROM dbo.PropertyTypes")
Do While Not RS.Tables(0).Rows.Count = 0
If RS.Fields(1).Value = sJob Then
GetG = RS.Fields(0).Value
GetG = Mid(GetG, 2, 36)
Exit Do
End If
DataSet.MoveNext
Loop
conn.Close
End Function
Based on my understanding and some guesswork, here is what I came up with for what I think you're wanting.
As I stated in my comment above, it appears you can just use a WHERE clause to get the exact record you want (assuming a single instance of sJob appears in the name column).
Build the connectionstring off the input arguments, not controls on your form. That is after all why you allow for arguments to be passed along. Also note that there is a SqlCommandBuilder object that may be of interest. But for now
Function GetG(sDB As String, sServ As String, sJob As String) As String
'we'll pretend your connectionstring is correct based off of the sDB and sServ arguments
Dim conStr As String = ("driver={SQL Server};server = " & sServ & " ; uid = username;pwd=password:database = " & sDB)
'Create a connection and pass it your conStr
Using con As New SqlConnection(conStr)
con.Open() 'open the connection
'create your sql statement and add the WHERE clause with a parameter for the input argument 'sJob'
Dim sql As String = "SELECT [ID], [Name] FROM dbo.PropertyTypes WHERE [Name] = #job"
'create the sqlCommand (cmd) and pass it your sql statement and connection
Using cmd As New SqlCommand(sql, con)
'add a parameter so the command knows what #job holds
cmd.Parameters.Add(New SqlParameter("#job", SqlDbType.VarChar)).Value = sJob
'Now that have the command built, we can pass it to a reader object
Using rdr As SqlDataReader = cmd.ExecuteReader
rdr.Read()
'i admin i'm a little confused here on what you are
'trying to achieve so ID may not be what you are
'really wanting to get a substring of.
Return rdr("ID").ToString.Substring(2, 36)
End Using
End Using
End Using
End Function
An example to see if this is working could be to call a messagebox do display the result. For this example, I'm going to pretend that TextBox3 holds the sJob you're wanting. With that knowledge, you could simply do:
MessageBox.Show(GetG(TextBox2.Text, TextBox1.Text, TextBox3.Text))
This should then produce the result in a messagebox.
It seems that you're not filling your DataSet. So, when you try to loop through it, it's uninitialized or empty.
Check this answer to see an example: Get Dataset from DataBase

sql query returning whole column of data

I have a VB.net program that parses a set of variables into a sub that I use to communicate with an Access Database.
The query string reads:
SELECT ID FROM cbRooms WHERE #condition
#condition is given a value with the code:
.Parameters.AddWithValue("#condition", dbCondition)
Where dbCondition is, in this case:
H_Block=True
When I run this query within Access directly, I get the expected data back, which is a set of numbers, that have a ticked box in Access
However, when I run that same code in Visual Studio, it just returns the whole column, regardless of whether the tick box is true or not
It's been a while since i've written something in VB, so i'm quite rusty, and therefore the problem is likely a simple oversight on my part
Here is the code for the sql access function:
Public Function sqlSelect(ByVal dbCol As String, ByVal dbTable As String, ByVal dbCondition As String)
'Creating the sqlCmd string to sent as an SQL request to the Database
Dim sqlCmd As String
'Creating a new connection to the database
Dim conn As New OleDb.OleDbConnection
'Setting the value for the sqlCmd string, with several "#" parameters
sqlCmd = "SELECT " & dbCol & " FROM " & [dbTable] & " WHERE #condition;"
'Running the Connect Sub routine to interact with the database
Connect(conn)
Using conn
Using dbEvent As New OleDb.OleDbCommand
With dbEvent
'sets the connection used by the current instance of OleDB usng the conn string
.Connection = conn
'Sets how the .CommandType is interpreted
.CommandType = CommandType.Text
'Sets the sqlCmd string that will be sent
.CommandText = sqlCmd
'Setting the "#" parameters in the sqlCmd string using values parsed into the sub routine
.Parameters.AddWithValue("#condition", dbCondition)
End With
Try
'Opening connection to the database
conn.Open()
'Creating the _sqlRead Reader used to read the data coming from the database
Dim sqlReader As OleDb.OleDbDataReader
sqlReader = dbEvent.ExecuteReader()
'Creates a list that will store the values returned to the Search.vb class
Dim returnVals As New List(Of Integer)
Do While sqlReader.Read = True
returnVals.Add(sqlReader(dbCol))
Loop
Return returnVals
Catch ex As Exception
'Opens a message box showing the current error
MessageBox.Show(ex.Message.ToString(), "Error Message")
End Try
End Using
End Using
End Function
And Here is the code for the combo box that calls the AccessSQL.vb:
Public Sub cbBlock_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cbBlock.SelectedIndexChanged
Select Case cbBlock.Text
Case "H Block"
cbRoom.Items.Clear()
Dim listOfRoomsInBlock As New List(Of Integer)
listOfRoomsInBlock = sqlSelect("ID", "cbRooms", "H_Block=True")
For x = 0 To listOfRoomsInBlock.Count - 1
cbRoom.Items.Add(listOfRoomsInBlock(x))
Next
Case "Tech Block"
cbRoom.Items.Clear()
Dim listOfRoomsInBlock As New List(Of Integer)
listOfRoomsInBlock = sqlSelect("ID", "cbRooms", "T_Block=True")
For x = 0 To listOfRoomsInBlock.Count - 1
cbRoom.Items.Add(listOfRoomsInBlock(x))
Next
End Select
End Sub
Thanks for any help!
EDIT:
The SQL, when run in VB returns This into the combo box I'm trying to populate
The 1 - 13 values at the bottom is what I'm expecting, whereas the 14 - 30 is not. My thinking is that my parameterisation is never actually using the condition I set above.
However, when I run that same, expected query, inside Access, I get the right values returned

out of range error in vb.net and access get maxnumber

iam trying to get the max number from table and insert it to another number
with vb.net 2008 and access db 2003 this my code
Dim strQ As String = "SELECT MAX(IDbatch) from batches "
Dim IDbatch As Integer
Dim cmdQ As OleDbCommand = New OleDbCommand(strQ, con)
If Not con.State = ConnectionState.Open Then
con.Open()
End If
Dim QReader As OleDbDataReader
Dim it As Integer
QReader = cmdQ.ExecuteReader
If QReader.FieldCount > 0 Then
While QReader.Read
it = QReader.Item("IDbatch")
MsgBox(it)
End While
End If
I am getting Out of range error
Change your query to
Dim strQ As String = "SELECT MAX(IDbatch) as MaxIDbatch from batches "
and your code that read the value to
it = QReader.Item("MaxIDbatch")
As you have it now the MAX(IDbatch) creates a field with a different name than IDbatch and trying to retrieve the content of that field using the name IDbatch fails giving the Index out of range exception
By the way, your check for FieldCount > 0 will be always true also in cases where there is no record in the batches table. So, if you have done that to protect in case of no record, then it is better to write
Dim result = cmdQ.ExecuteScalar()
if result IsNot Nothing then
Dim it = Convert.ToInt32(result)
MsgBox(it)
End If
And with this approach you could also leave out the aliasing on the IDbatch field

How to select checked item in data Grid using linq

i have a data grid (using component one's control) and this data grid have a check box value item to select some of the rows, the given below is my grid
i use the check box to select rows for delete or update
at this moment am using for loop to iterate through my grid
i think in .net using linq is more better than for loop
given below is my code to iterate through grid using for loop
Private Sub deleteGtab81()
Dim intcount As Integer
Dim intdistid As Integer
Dim command, commandReader As New NpgsqlCommand
command.Connection = GenConnection()
commandReader.Connection = command.Connection
command.CommandType = CommandType.Text
commandReader.CommandType = CommandType.Text
For intcount = 0 To grdDistricts.Rows.Count - 1
If grdDistricts(intcount, "S").ToString <> "" Then
If grdDistricts(intcount, "S").ToString = 1 Then
intdistid = grdDistricts(intcount, "talukid").ToString()
command.CommandText = "delete from gtab81 where talukid='" & intdistid & "' "
command.ExecuteNonQuery()
End If
End If
Next
grdDistricts.Rows.Clear()
FillGrddistricts()
FillCbodistricts()
End Sub
So how to use linq to get the selected rows ?
NOTE : code is written in vb.net
T.I.A
I've never really tried to use LINQ against a DataGridViewRowCollection, but I suppose you should write something like that:
C#
IList<int> result = (from row in grdDistricts.Rows.OfType<DataGridViewRow>()
where !string.IsNullOrEmpty(row.Cells["S"].Value.ToString()) &&
(int)row.Cells["S"].Value == 1
select (int)row.Cells["talukid"].Value).ToList();
VB.NET
Dim list As IList(Of Integer) = (From row In grdDistricts.Rows.OfType(Of DataGridViewRow)() _
Where Not String.IsNullOrEmpty(row.Cells("S").Value.ToString()) AndAlso _
row.Cells("S").Value = 1 _
Select DirectCast(row.Cells("talukid").Value, Integer)).ToList()
This will select all yours "talukid" and place them in a list.