.NET How to get Sql response to string? - sql

After inserting something into the DB I would like to get the server's response.
For example "x rows effected" or other messages, and put them into a string variable.
How do I implement this in code? C# or VB - doesn't matter to me.
I couldn't find anything specific on this, but I am a n00b # programming.
Thank you kindly.Could you kindly provide an example for me? Here is my code:
Private Function insertScr(ByVal byte2insert As Byte()) As Boolean
Dim _con As SqlConnection
Dim queryStmt As String
Dim _cmd As SqlCommand
Dim param As SqlParameter
Try
_con = New SqlConnection(My.Settings.DBconnStr)
queryStmt = "update ErrorLog set screen = #Content where(ErrorLogID = 2)"
_cmd = New SqlCommand(queryStmt, _con)
param = _cmd.Parameters.Add("#Content", SqlDbType.VarBinary)
param.Value = byte2insert
_con.Open()
_cmd.ExecuteNonQuery()
_con.Close()
Return True
Catch ex As Exception
Return False
End Try
End Function

Assuming SQL Server, the SqlConnection object has an InfoMessage event that is raised for each of these sorts of messages (it also has a mode that can be enabled so that error messages are delivered via the same event, see FireInfoMessageEventOnUserErrors)
You would access the text of these messages by extracting the Message property from the second argument passed to your event handler.
Something like:
...
_con = New SqlConnection(My.Settings.DBconnStr)
AddHandler _con.InfoMessage,Sub(sender,e)
MessageBox.Show(e.Message)
End Sub
queryStmt = "update ErrorLog set screen = #Content where(ErrorLogID = 2)"
...

The ExecuteNonQuery() method of the ADO .NET SQLCommand returns rows affected count.
Stored procedures can return values through output parameters or through RETURN value parameter

Private Function insertScr(ByVal byte2insert As Byte()) As Boolean
Dim _con As SqlConnection
Dim queryStmt As String
Dim _cmd As SqlCommand
Dim param As SqlParameter
Dim RowsAffected as Int
Try
_con = New SqlConnection(My.Settings.DBconnStr)
queryStmt = "update ErrorLog set screen = #Content where(ErrorLogID = 2)"
_cmd = New SqlCommand(queryStmt, _con)
param = _cmd.Parameters.Add("#Content", SqlDbType.VarBinary)
param.Value = byte2insert
_con.Open()
RowsAffected = _cmd.ExecuteNonQuery()
_con.Close()
Return True
Catch ex As Exception
Return False
End Try
End Function

Related

How to factorize calls to ado.net with parameters?

i want to factorize all the calls to ado.net present in my web application to not repeat over and over the connection string and the open/close methods. I succeed to do it for the calls without parameter, but i need help for the ones with parameters.
For example, I had :
Dim strConnexion As String = "myConnectionString"
Dim strRequete As String = "DELETE FROM tbl_devis WHERE id_devis = " + TBDevis.Text
Dim oConnection As New SqlConnection(strConnexion)
Dim oCommand As New SqlCommand(strRequete, oConnection)
oConnection.Open()
oConnection.ExecuteNonQuery()
oConnection.Close()
I factorized it into :
ExecuteRequest("DELETE FROM tbl_devis WHERE id_devis = " + TBDevis.Text)
And the code of ExecuteRequest :
Public Shared Sub ExecuteRequest(ByVal strRequest As String)
Dim strConnection As String = ChaineDeConnexion()
Using objConnection = New SqlConnection(strConnection)
Dim objCommand As SqlCommand
objCommand = New SqlCommand(strRequest, objConnection)
objCommand.Connection.Open()
objCommand.ExecuteNonQuery()
End Using
End Sub
But I would like be able to pass to Execute request a collection of parameters. This is a very simple example of what kind of code I want to factorize :
Dim strConnexion As String = "myConnectionString"
Dim strRequete As String = "DELETE FROM tbl_devis WHERE id_devis = #id_devis"
Dim oConnection As New SqlConnection(strConnexion)
Dim oCommand As New SqlCommand(strRequete, oConnection)
With (myCommand.Parameters)
.Add(New SqlParameter("#id_devis", SqlDbType.Int))
End With
With myCommand
.Parameters("#id_devis").Value = TBDevis.Text
End With
oConnection.Open()
oConnection.ExecuteNonQuery()
oConnection.Close()
I was thinking about edit my ExecuteRequest function to add an optional parameters collection :
Public Shared Sub ExecuteRequest(ByVal strRequest As String, Optional ByRef sqlParameters As SqlParameterCollection = Nothing)
Dim strConnection As String = ChaineDeConnexion()
Using objConnection = New SqlConnection(strConnection)
Dim objCommand As SqlCommand
objCommand = New SqlCommand(strRequest, objConnection)
objCommand.Parameters = sqlParameters 'objCommand.Parameters is readonly property
objCommand.Connection.Open()
objCommand.ExecuteNonQuery()
End Using
End Sub
But VS tell me that objCommand.Parameters is a readonly property...
I see two solutions :
Passing an array containing the parameter name, value and type, and looping through the array
Creating the string request with all the parameters like that : "DELETE FROM tbl_devis WHERE id_devis = " + TBDevis.Text ... but when there are 30 parameters, this is a dirty solution I guess ?
Which one would be the cleaner, strongest solution please ?
Thanks for your help !
ParamArray is what you're looking for.
Update your ExecuteRequest like this:
Public Sub ExecuteRequest(ByVal strRequest As String, ParamArray Params() As SqlParameter)
Dim strConnexion As String = "myConnectionString"
Using Conn As New SqlConnection(strConnexion), Cmd As New SqlCommand(strRequest, Conn)
Cmd.Parameters.AddRange(Params)
Conn.Open()
Cmd.ExecuteNonQuery()
End Using
End Sub
and then you can call it like
ExecuteRequest("DELETE FROM tbl_devis WHERE id_devis = #id_devis", New SqlParameter("#id_devis", CInt(TBDevis.Text)))
I would also suggest to create function sqlPar(Name As String, Value As Object) with few more overloads to simplify the call to
ExecuteRequest("DELETE FROM tbl_devis WHERE id_devis = #id_devis", sqlPar("#id_devis", TBDevis.Text))
ParamArray allows you to add undefined amount of arguments like this
ExecuteRequest("SELECT ID FROM Table WHERE ID IN (#A, #B, #C, #D)", sqlPar("#A", 1), sqlPar("#B", 2), sqlPar("#C", 3), sqlPar("#D", 4))
You should ALWAYS use SqlParameter instead of string concatenation to prevent SQL injections.
You should ALWAYS use Using for IDisposable resources as well.

Variable 'reader' is used before it has been assigned a value. A null reference exception could result at run time

Trying to fix a warning and not sure how to restructure code as reader.IsClosed is throwing a warning that states "Variable 'reader' is used before it has been assigned a value. A null reference exception could result at run time." Logistically, since reader As SqlDataReader && reader is not initialized with a value then I could ignore as should be fine at runtime, but my inexperience would make me believe there is a better way?
Public Function GetTotalItems(ByVal userId As Long) As Int16
Dim lstParam As List(Of SqlParameter) = New List(Of SqlParameter)()
Dim tablMd = Me.GetMetaData()
Dim retList As ArrayList = New ArrayList()
lstParam.Add(New SqlClient.SqlParameter("#" + tablMd.PrimaryKey.ColumnName, 0))
lstParam.Add(New SqlClient.SqlParameter("#UserID", userId))
lstParam.Add(New SqlClient.SqlParameter("#ActionFlag", "SELECT_ITEMS_COUNT"))
Dim spName As String = Me.GetStoreProcname()
Dim reader As SqlDataReader
Try
reader = SqlHelper.ExecuteReader(
Utility.GetConnectionStringSetting(),
CommandType.StoredProcedure,
Me.GetStoreProcname(),
lstParam.ToArray()
)
If (reader.HasRows = True) Then
If (reader.Read()) Then
Dim value As Object = reader(0)
Return CInt(value)
End If
End If
Catch ex As Exception
Throw
Finally
If Not reader.IsClosed Then
reader.Close()
End If
End Try
Return 0
End Function
We can narrow the problem down to this excerpt:
Dim reader As SqlDataReader
Try
reader = SqlHelper.ExecuteReader( ... )
Finally
If Not reader.IsClosed Then reader.Close()
End Try
The problem comes if an exception is thrown by the ExecuteReader() function. In that event, the reader variable is never assigned a value. It's still Nothing when you try to evaluate reader.IsClosed, and that will cause an exception.
Given you don't actually do anything with the exception and the SqlHelper takes care of the connection and command objects, you can narrow the entire function down to just this:
Public Function GetTotalItems(ByVal userId As Long) As Int16
Dim lstParam = {
New SqlClient.SqlParameter("#" + Me.GetMetaData().PrimaryKey.ColumnName, 0),
New SqlClient.SqlParameter("#UserID", userId),
New SqlClient.SqlParameter("#ActionFlag", "SELECT_ITEMS_COUNT")
}
Using reader As SqlDataReader = SqlHelper.ExecuteReader(
Utility.GetConnectionStringSetting(),
CommandType.StoredProcedure,
Me.GetStoreProcname(),
lstParam)
If reader.Read() Then Return CInt(reader(0))
End Using
Return 0
End Function
#jmcilhinney, #o_O, #Chris Dunaway ... Thank you for the help + appreciation + admiration for your knowledge + reverence == deverence(); ... This removed the error:
Public Function GetTotalAmount(ByVal userId As Long) As Decimal
Dim lstParam As List(Of SqlParameter) = New List(Of SqlParameter)()
Dim tablMd = Me.GetMetaData()
Dim retList As ArrayList = New ArrayList()
lstParam.Add(New SqlClient.SqlParameter("#" + tablMd.PrimaryKey.ColumnName, 0))
lstParam.Add(New SqlClient.SqlParameter("#UserID", userId))
lstParam.Add(New SqlClient.SqlParameter("#ActionFlag", "SELECT_TOTAL_AMOUNT"))
Dim spName As String = Me.GetStoreProcname()
Using reader As SqlDataReader = SqlHelper.ExecuteReader(
Utility.GetConnectionStringSetting(),
CommandType.StoredProcedure,
Me.GetStoreProcname(),
lstParam.ToArray()
)
If (reader.HasRows = True) Then
If (reader.Read()) Then
Dim value As Object = reader(0)
Return CDec(value)
End If
End If
End Using
Return 0
End Function

VB.Net freezing when adding 10000+ rows to SQL from list

I am running a RESTful API service which gets data from a server as a JSON string. Around 20000 rows are being selected.
Dim js As New JavaScriptSerializer()
Dim prodlist As List(Of Product) = js.Deserialize(Of List(Of Product))(JSONreturn)
The 20000 rows are populated in the list prodlist. Checked the count and manually verified the list.
I need to insert these rows in a client machine. However, while inserting the rows, it freezes or stops after inserting around 600-700 rows. Below is the code I am using for inserting.
For Each item As Product In prodlist
Dim SPName As String = "someSPname"
With connectionstring
.Clear()
.Parameters("#itemnumber", SqlDbType.VarChar, ParameterDirection.Input, , item.itemnumber
.Parameters("#itemtype", SqlDbType.VarChar, ParameterDirection.Input, , item.itemtype)
.Parameters("#DESCRIPTION", SqlDbType.VarChar, ParameterDirection.Input, , item.DESCRIPTION)
.Execute(SPName)
End With
Next
No error is thrown. It just freezes after inserting roughly 600-700 rows everytime.
Bulk insert is not an option. How do I resolve this?
UPDATE : Adding connection class. Pretty sure there is no issue with this :
Public Class ConnectionClass
Public ReadOnly Property ConnectionString() As String
Get
Return GetConfiguration()
End Get
End Property
Public Sub Parameters(ByVal param_name As String, ByVal type As SqlDbType, ByVal direction As ParameterDirection, Optional param_size As Int32 = Nothing, Optional param_value As Object = Nothing)
Dim sqlParam As SqlParameter = Nothing
Try
sqlParam = New SqlParameter(param_name, type)
sqlParam.Size = param_size
sqlParam.Direction = direction
sqlParam.Value = param_value
Lstparam.Add(sqlParam)
Finally
If sqlParam IsNot Nothing Then
sqlParam = Nothing
End If
End Try
End Sub
Public Sub Execute(ByVal strSpName As String, Optional ByVal Type As CommandType = CommandType.StoredProcedure)
Try
sqlcmd = New SqlCommand()
sqlcmd.Connection = connection
''Setting the timeout to 50 mins as setup in the previous application
sqlcmd.CommandTimeout = 3000
If transaction IsNot Nothing Then
sqlcmd.Transaction = transaction
End If
sqlcmd.CommandType = Type
sqlcmd.CommandText = strSpName
For Each argument As SqlParameter In Lstparam
sqlcmd.Parameters.Add(argument)
Next
For introw As Integer = 0 To sqlcmd.Parameters.Count - 1
If sqlcmd.Parameters.Item(introw).ParameterName.Contains("Parameter") Then
sqlcmd.Parameters.Item(introw).ParameterName = String.Empty
End If
Next
sqlcmd.ExecuteNonQuery()
Catch ex As Exception
Throw
End Try
End Sub
Public Sub Clear()
ClearParameters()
Lstparam.Clear()
End Sub
Public Sub ClearParameters()
If Not sqlcmd Is Nothing Then
Do Until sqlcmd.Parameters.Count = 0
sqlcmd.Parameters.Clear()
Loop
End If
End Sub
Public Function GetConfiguration() As String
Dim sbConnectionString As New StringBuilder
With sbConnectionString
.Append("Data Source=")
.Append(ServerName)
.Append(";")
.Append("Initial Catalog =")
.Append(DatabaseName)
.Append(";")
.Append("User ID =")
.Append(UserName)
.Append(";")
.Append("Password =")
.Append(UserPassword)
End With
Return sbConnectionString.ToString()
End Function
Public Function CreateClientConnection() As SqlConnection
Dim connectionString As String
Try
connectionString = GetConfiguration()
Dim substrings() As String = connectionString.ToUpper.Split(";")
Dim substrings1() As String = connection.ConnectionString.ToUpper.Split(";")
If Not (connection.State = ConnectionState.Open) Then
connection.ConnectionString = connectionString
connection.Open()
ElseIf Not (Trim(substrings(0)) = Trim(substrings1(0))) Then
If connection IsNot Nothing Then
connection.Dispose()
End If
connection.ConnectionString = connectionString
connection.Open()
End If
Return connection
Catch ex As Exception
If connection IsNot Nothing Then
connection.Dispose()
End If
Throw ex
End Try
End Function
End Class

Procedure or function 'p_xxx ' has too many arguments specified

I get the error at this line: sqlDataAdapDelProtocol.Fill(dsDelProtocol, "dsProtocols"), I dint understand why. The error states : Procedure or function p_GetLinkedProcuduresProtocol has too many arguments specified
Protected Sub btnDeletePTC_Click(ByVal sender As Object, ByVal e As EventArgs)
Dim sqlString As String = String.Empty
Dim PTC_ID As Integer
sqlString = "p_GetLinkedProcuduresProtocol"
Dim sqlConnDelProtocol As New SqlClient.SqlConnection(typicalConnectionString("MyConn").ConnectionString)
sqlConnDelProtocol.Open()
Dim sqlDataAdapDelProtocol As New SqlClient.SqlDataAdapter(sqlString, sqlConnDelProtocol)
sqlDataAdapDelProtocol.SelectCommand.CommandType = CommandType.StoredProcedure
Dim sqlParProtocolName As New SqlClient.SqlParameter("#PTC_ID", SqlDbType.Int, 255)
sqlDataAdapDelProtocol.SelectCommand.Parameters.Add(sqlParProtocolName)
Dim dsDelProtocol As New DataSet
Dim MessageAud = "Are you sure you want to delete this question, the question is linked to:"
Dim MessageNoAud = "Are you sure you want to delete this question"
sqlDataAdapDelProtocol.SelectCommand.Parameters.AddWithValue("PTC_ID", PTC_ID)
sqlDataAdapDelProtocol.Fill(dsDelProtocol, "dsProtocols")
If dsDelProtocol.Tables("dsProtocols").Rows.Count > 0 Then
lblMessageSure.Text = (CType(MessageAud, String))
For Each dr As DataRow In dsDelProtocol.Tables(0).Rows
lblAudits = (dr("dsProtocols"))
Next
Else
lblMessageSure.Text = (CType(MessageNoAud, String))
End If
Dim success As Boolean = False
Dim btnDelete As Button = TryCast(sender, Button)
Dim row As GridViewRow = DirectCast(btnDelete.NamingContainer, GridViewRow)
Dim cmdDelete As New SqlCommand("p_deleteProtocolStructure")
cmdDelete.CommandType = CommandType.StoredProcedure
cmdDelete.Parameters.AddWithValue("PTC_ID", PTC_ID)
Call DeleteProtocol(PTC_ID)
conn = NewSqlConnection(connString, EMP_ID)
cmdDelete.Connection = conn
If Not conn Is Nothing Then
If conn.State = ConnectionState.Open Then
Try
success = cmdDelete.ExecuteNonQuery()
Call UpdateProtocolNumbering(PTS_ID)
txtAddPTCNumber.Text = GetNextNumber(PTS_ID)
Page.ClientScript.RegisterClientScriptBlock(Me.GetType(), "TreeView", _
"<script language='javascript'>" & _
" parent.TreeView.location='TreeView.aspx?MainScreenURL=Protocols.aspx&PTS_ID=" & PTS_ID & "';" & _
"</script>")
conn.Close()
Catch ex As Exception
success = False
conn.Close()
Throw ex
End Try
End If
End If
If success = True Then
Call GenerateQuestionsGrid()
Call Message(Me, "pnlMessage", "Question successfully deleted.", Drawing.Color.Green)
Else
Call Message(Me, "pnlMessage", "Failed to delete Question.", Drawing.Color.Red)
End If
End Sub
You are adding the same parameter twice, once without a value, then with a value. Instead of adding it another time, set the value on the parameter that you already have.
Replace this:
sqlDataAdapDelProtocol.SelectCommand.Parameters.AddWithValue("PTC_ID", PTC_ID)
with this:
sqlParProtocolName.Vaue = PTC_ID
Side note: Always start parameter names for Sql Server with #. The parameter constructor will add it if it's not there so it will work without it, but this is an undocumented feature, so that could change in future versions.

Object reference not set to an instance of an object when calling a function

I call the function GetDataTable and when it gets to the return line, I get the error message:
Object reference not set to an instance of an object.
Dim DB As New DBConn
Dim gd As New DataAccess.GetData
Dim DT As New DataTable
Dim repotid1 As Decimal = 1150
Dim startdata1 As DateTime = "6/1/2012"
Dim EndDate1 As DateTime = "6/12/2012"
Dim StartDate3 As DateTime = "11/1/2011"
Dim Enddate3 As DateTime = "5/1/2012"
Dim sql1 As String = String.Format("EXEC [dbo].[usp_GetReportData_All] #ReportID=N'{0}', #StartDate=N'{1}' #EndDate=N'{2}', #StartDate2=N'{3}' #EndDate2=N'{4}'", repotid1, startdata1, EndDate1, StartDate3, Enddate3)
DT = DB.GetDataTable(sql1)
Public Class DBConn
Dim gd As New DataAccess.GetData
Public Function GetDataTable(ByVal sql As String) As DataTable
Dim _appID As String = "IS"
Dim _transID As String = "MSSQL01"
Return gd.getDataTable(_appID, _transID, sql) 'I get the error message here
End Function
End Class
Updated. I'll see if I can update with the DataAccess.GetData code. I didn't originally put it in there because our shop use it all the time and have no issues with it.
Without seeing what's in gd.getDataTable, there's not a lot we can do to help you. What kind of application are you writing that is calling this function? Can you put a breakpoint on that line in the editor and step into it to see where the error is occurring? Otherwise, do you have access to the DataAccess.GetData code? If so, you would get a lot more information from it if you threw the original exception without destroying the stack trace:
BAD!!!!
Try
'your code
Catch ex As Exception
Throw New Exception(ex.Message)
End Try
GOOD:
Try
'your code
Catch ex As Exception
Throw
End Try