What would cause my dataset to drop a row? - vb.net

I have a SQL statement that, when ran in SSMS, returns 6 rows. After attaching the statement to the command text of a VB.NET SQLCommand with a command type of Text, reading it with a SqlDataReader, and attaching it to a dataset, the returned dataset only has 5 rows.
At first, I assumed it was an issue with the data. However, after several bouts of removing and adding rows to the source table with varying data, it was obvious that I was always getting the total row count - 1. I then decided to just use a SQLDataAdapter to populate the DataSet and the proper number of rows was returned.
Dim ds As New DataSet
Dim sqlCmd as New SqlCommand
Dim sqlCn As New SqlConnection
Dim sqlR As New SqlCommand
sqlCn.ConnectionString = "SomeConnectionString"
With sqlCmd.CommandText = "Select * from DummyTable"
.CommandType = CommandType.Text
.Connection = sqlCn
End With
sqlCn.Open()
sqlR = sqlCmd.ExecuteReader
sqlR.Read()
If sqlR.HasRows() Then
ds.Tables.Add("DummyTable")
ds.Tables(0).Load(sqlR)
return ds
End If
From here, I'm expecting to see the 6 rows from DummyTable. Instead, I'm seeing only 5.
However, if I use the following:
Dim da as SqlDataAdapter
Using sqlCn
da.SelectCommand = New SqlCommand(sqlCmd.CommandText, sqlCn)
da.Fill(ds)
End Using
Return ds
I get the full 6 rows. Is there something I'm missing about the way a DataSet's Tables.Add(tableName) or Tables(n).Load(dataReader) works? I had never worked with SqlDataReaders prior to this and was told to stick with them as our other projects use them.

Your code is already reading the first line of the query with the line sqlR.Read(). This line is unnecessary in your code. Remove it and it will work fine.
Also SqlCommand, SqlConnection and SqlDataReader implement iDisposable, so be sure to use using-statement with them:
Using sqlCn As New SqlConnection("SomeConnectionString")
sqlCn.Open()
Using sqlCmd as New SqlCommand
With sqlCmd.CommandText = "Select * from DummyTable"
.CommandType = CommandType.Text
.Connection = sqlCn
End With
Using sqlR As SqlDataReader = sqlCmd.ExecuteReader
If sqlR.HasRows() Then
Dim ds As New DataSet
ds.Tables.Add("DummyTable")
ds.Tables(0).Load(sqlR)
return ds
End If
End Using
End Using
End Using

Related

VB.NET - Stored procedure runs but parameters aren't working

I have the following bit of code:
Dim SQLCon As New SqlConnection
Dim cmd As New SqlCommand
Dim ds As New DataSet
SQLCon.ConnectionString = ConfigurationSettings.AppSettings("myConnString")
SQLCon.Open()
cmd.CommandType = CommandType.StoredProcedure
'run the stored procedure based on the view selected
If rdolstView.Items(0).Selected Then
cmd = New SqlCommand("spCondensedView", SQLCon)
ElseIf rdolstView.Items(1).Selected Then
cmd = New SqlCommand("spExtendedView", SQLCon)
End If
'filter by what the user searched for
If ddlSearchBy.SelectedValue = "Member" Then
cmd.Parameters.AddWithValue("#MbrNum", txtSearchFor.Text)
ElseIf ddlSearchBy.SelectedValue = "Assistant" Then
cmd.Parameters.AddWithValue("#AssignedAsst", ddlUWAssistants.SelectedValue)
ElseIf ddlSearchBy.SelectedValue = "Rep" Then
cmd.Parameters.AddWithValue("#Rep", txtSearchFor.Text)
ElseIf ddlSearchBy.SelectedValue = "Dept Assistant" Then
cmd.Parameters.AddWithValue("#DeptAsst", txtSearchFor.Text)
ElseIf ddlSearchBy.SelectedValue = "Creator" Then
cmd.Parameters.AddWithValue("#Creator", txtSearchFor.Text)
End If
Dim da As New SqlDataAdapter(cmd)
da.Fill(ds)
SQLCon.Close()
My problem is that the parameters don't seem to be working. Both stored procedures are supposed to take the optional parameter (either #MbrNum, #AssignedAsst, #Rep, #DeptAsst, or #Creator) and filter by it in its WHERE clause.
I've confirmed that this is working properly when I run the stored procedures manually in SQL Server Management Studio. I've also confirmed that the If/ElseIf statements are validating as true properly. So my code is definitely hitting the AddWithValue() statements when it's supposed to.
My returned result, however, is the full dataset without the filters applied, as if I ran the stored procedure with no parameters specified.
Any help would be awesome. Thanks!
Try specifying the a Command.Type...Set this when you create the command object.
cmd.CommandType = CommandType.StoredProcedure
By default it's set as Text I believe... Also wrap your connection and command's in Using statements so they are properly handled when done...

Selecting different connection strings for data gridview

Why is this not straight-forward? I have two databases that contain a log-table each. I have a stored procedure that extracts the data from the table. I have a datagridview on a windows form, and a drop-down box to select the connection string for the respective databases. On selection of the conn string, I want to change the datagridview to contain the log messages in the selected database.
My code:
Select Case cboConnection.Text
Case "CP DEV"
LogConnectionString = "Data Source=SAMBAR.gofast.com;Initial Catalog=CPDev;User ID=gofastconfig;Password=gofastdev;"
Case "CP LIVE"
LogConnectionString = "Data Source=SAMBAR.gofast.com;Initial Catalog=CPLive;User ID=gofastconfig;Password=gofastlive;"
End Select
Dim cmd As New SqlCommand("dbo.getLogMessages")
Using con As New SqlConnection(LogConnectionString)
Using sda As New SqlDataAdapter()
cmd.Connection = con
cmd.CommandType = CommandType.StoredProcedure
sda.SelectCommand = cmd
sda.Fill(Me.CustomerPulseDBDataSet1)
con.Close()
gridLog.DataSource = Me.CustomerPulseDBDataSet1.Tables(0)
End Using
End Using
First, I don't see you open your connection. Then, you got it a bit up side down...
Using con As New SqlConnection(LogConnectionString)
con.Open()
Using cmd As New SqlCommand("dbo.getLogMessages", con)
cmd.CommandType = CommandType.StoredProcedure
Using da As New SqlDataAdapter(cmd)
' We need to clear out old data before reloading if same DS instance used
If Me.CustomerPulseDBDataSet1.Tables.Count > 0 Then
Me.CustomerPulseDBDataSet1.Tables.Clear()
End If
da.Fill(Me.CustomerPulseDBDataSet1)
End Using
End Using
con.Close()
End Using
gridLog.DataSource = Me.CustomerPulseDBDataSet1.Tables(0)
Should work perfectly every time

AutocompleteExtender from a 65000 record in sql table

I'm trying to Autocomplete City names from a huge sql table. My code below work but its very slow and sometimes it freezes because I got a lot repeated suggestions. any way to filter all this repeated string to make it faster ? thanks
Public Function GetCompletionList(ByVal prefixText As String, ByVal count As Integer) As String()
Dim strCn As String = "Data Source=sqlserver\sqlexpress;Initial Catalog=zip;User ID=sa;Password=xxx"
cn.ConnectionString = strCn
Dim cmd As New SqlClient.SqlCommand
cmd.Connection = cn
cmd.CommandType = CommandType.Text
cmd.CommandText = "select * from zip_code Where City like #myParameter+'%'"
cmd.Parameters.AddWithValue("#myParameter", prefixText)
Try
cn.Open()
cmd.ExecuteNonQuery()
Dim da As New SqlDataAdapter(cmd)
Dim dt As New DataTable()
da.Fill(ds)
Catch ex As Exception
Finally
cn.Close()
End Try
dt = ds.Tables(0)
Dim txtItems As New List(Of String)()
Dim dbValues As String
For Each row As DataRow In dt.Rows
dbValues = row("City").ToString()
dbValues = dbValues.ToLower()
txtItems.Add(dbValues)
Next
Return txtItems.ToArray
You are executing your SQL twice, once during ExecuteNonQuery, second time during Fill.
You are not using IDisposable objects correctly.
You return all columns.
If you have a control for display, check if it will accept Rows (Dataset?) property directly. Don't copy.
UPDATE
Your connection, command and other objects implement an IDisposable interface. So they should be placed in a using block:
Using { resourcelist | resourceexpression }
[ statements ]
End Using
Then you don't have to worry about closing and disposing a database connection.
UPDATE 2
Your code has thread safety issues, the same connection must not be shared by two different threads. EVER. Two consecutive Fill request and one will close the database connection before the other can finish.

Is filling a DataTable necessary for just setting variables with 2 column values?

I am trying to improve performance of an application, I have a case where a common SPROC is being used but is it necessary to fill a DataTable just to set 2 variable values?
Is there anything more efficient?
Dim Conn As SqlConnection = New SqlConnection(ConfigurationManager.ConnectionStrings("DB").ConnectionString)
Dim CmdUsers As SqlCommand = New SqlCommand("uspGetUsers", Conn)
CmdUsers.CommandType = CommandType.StoredProcedure
CmdUsers.Parameters.Add(New SqlParameter("#UserName", Session("UserID")))
Dim da As SqlDataAdapter = New SqlDataAdapter
Dim dtUserInfo As DataTable = New DataTable
da = New SqlDataAdapter(CmdUsers)
da.Fill(dtUserInfo)
isParent = dtUserInfo.Rows(0)("IsAdmin")
UserVal = dtUserInfo.Rows(0)("UserVal")
A SqlDataReader is the fastest way to read data from a query. Try the following:
Using conn As SqlConnection = New SqlConnection(ConfigurationManager.ConnectionStrings("DB").ConnectionString)
conn.Open()
Using cmd As New SqlCommand("uspGetUsers", conn)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("#UserName", Session("UserID"))
Using reader As SqlDataReader = cmd.ExecuteReader()
While reader.Read()
isParent = reader("IsAdmin")
UserVal = reader("UserVal")
End While
End Using
End Using
End Using
You may need to parse the data to the correct types.
Also, note the use of Using to automatically dispose of the connection, command and reader objects: http://msdn.microsoft.com/en-GB/library/htd05whh.aspx

Showing data in textbox

I am trying to get data from a database (which I have done and know that works)
However I want to push the data into a variable.
I can not see what is wrong, at the moment there is a mistake around "cmd.select" so if someone could point me in the right direction that would be great!
Dim cn As SqlConnection = New SqlConnection()
Dim cmd As SqlCommand = New SqlCommand()
Dim sqladp As New SqlDataAdapter()
Dim ds As New DataSet()
cmd.Parameters.Clear()
cn.ConnectionString = ConfigurationManager.ConnectionStrings("PemcoConnectionString").ConnectionString
cmd.Connection = cn
GridView2.Visible = True
cmd.Connection = cn
cmd.CommandText = "spUserResultsDetails"
cmd.CommandType = CommandType.StoredProcedure
Session.Item("ID") = (sender.SelectedValue.ToString)
cmd.Parameters.AddWithValue("#ID", Session.Item("ID"))
For Each datarow As Data.DataRowView In cmd.Select(DataSourceSelectArguments.Empty)
sEmailAddress = datarow("UserEmail")
Next
sqladp.SelectCommand = cmd
sqladp.Fill(ds)
There are many things that need improvement, this should work:
Using cn = New SqlConnection(ConfigurationManager.ConnectionStrings("PemcoConnectionString").ConnectionString))
Using da = New SqlDataAdapter("spUserResultsDetails", cn)
da.SelectCommand.CommandType=CommandType.StoredProcedure
da.SelectCommand.Parameters.AddWithValue("#ID", CInt(Session.Item("ID")))
Dim table = New Data.DataTable()
da.Fill(table)
GridView2.DataSource = table
GridView2.DataBind()
End Using
End Using
A summary:
use the using statement always to ensure that disposable objects are getting disposed (closed) even on error
use a SqldataAdapter if you want to fill a DataTable, you don't need to open/close it with fill, use it's SelectCommand property to get a reference to the SqlCommand
set the table as DataSource of your GridView and DataBind it
if you use AddWithValue you should cast the passed objects to the correct type, otherwise the correct type cannot be inferred