I have this code to update my SQL database from data in a textbox, in VB. I need to use parameters in case the text contains a tic mark ,', or a quote ,", etc. Here is what I have:
dbConn = New SqlConnection("server=.\SQLEXPRESS;Integrated Security=SSPI; database=FATP")
dbConn.Open()
MyCommand = New SqlCommand("UPDATE SeansMessage SET Message = '" & TicBoxText.Text & _
"'WHERE Number = 1", dbConn)
MyDataReader = MyCommand.ExecuteReader()
MyDataReader.Close()
dbConn.Close()
And this is my lame attempt to set a parameter from what I have seen on the web, which I don't understand all that well.
dbConn = New SqlConnection("server=.\SQLEXPRESS;Integrated Security=SSPI; database=FATP")
dbConn.Open()
MyCommand = New SqlCommand("UPDATE SeansMessage SET Message = #'" & TicBoxText.Text & _
"'WHERE Number = 1", dbConn)
MyDataReader = MyCommand.ExecuteReader()
MyDataReader.Close()
dbConn.Close()
How do you do this? Cause if there is a ' mark in the textbox when I run the code, it crashes.
You are on the right path to avoiding Bobby Tables, but your understanding of # parameters is incomplete.
Named parameters behave like variables in a programming language: first, you use them in your SQL command, and then you supply their value in your VB.NET or C# program, like this:
MyCommand = New SqlCommand("UPDATE SeansMessage SET Message = #TicBoxText WHERE Number = 1", dbConn)
MyCommand.Parameters.AddWithValue("#TicBoxText", TicBoxText.Text)
Note how the text of your command became self-contained: it no longer depends on the value of the text from the text box, so the users cannot break your SQL by inserting their own command. #TicBoxText became a name of the variable that stands for the value in the text of the command; the call to AddWithValue supplies the value. After that, your ExecuteReader is ready to go.
There are a number of improvements in here:
Using dbConn As New SqlConnection("server=.\SQLEXPRESS;Integrated Security=SSPI; database=FATP"), _
MyCommand As SqlCommand("UPDATE SeansMessage SET Message = #Message WHERE Number = 1", dbConn)
'Make sure to use your exact DbType (ie: VarChar vs NVarChar) and size
MyCommand.Parameters.Add("#Message", SqlDbType.VarChar).Value = TicBoxText.Text
dbConn.Open()
MyCommand.ExecuteNonQuery() ' don't open a data reader: just use ExecuteNonQuery
End Using 'Using block will close the connection for you
Related
Currently I'm developing a student portal with an appropriate and simple login system for my college's final year project purpose. This is one of the command button (to save photo to SQL server) I've encountered error. This is the error statement:
System.Data.SqlClient.SqlException: 'String or binary data would be truncated.
The statement has been terminated.'
Private Sub Button8_Click(sender As Object, e As EventArgs) Handles Button8.Click
'String imagelocation = ""
Dim images() As Byte = Nothing
'Dim imagelocation As String
'imagelocation = ""
Dim Stream As New FileStream(imagelocation, FileMode.Open, FileAccess.Read)
Dim brs As New BinaryReader(Stream)
images = brs.ReadBytes(CInt(Stream.Length))
Dim source As String = "Data Source=LAPTOP-85ALBAVS\SQLEXPRESS;Initial Catalog=Portal;Integrated Security=True"
Dim con As New SqlConnection(source)
con.Open()
Dim cmd As String = "Insert into Photo Values('" + TextBox2.Text + "', #images)"
Dim qry As New SqlCommand(cmd, con)
qry.Parameters.Add(New SqlParameter("#images", images))
'qry.Parameters.Add(new SqlParameter("#images", pictureBox1));
***Dim i As Integer = qry.ExecuteNonQuery()
If i >= 1 Then
MessageBox.Show("Successfull!", "message", MessageBoxButtons.OK)
Else
MessageBox.Show("Fail!", "message", MessageBoxButtons.OK)
End If
End Sub
End Class
This is a SQL table for me to save the uploaded photo into database. Any help would be appreciated. Thanks.
UPDATE
PreviouslyPhotocolumn name changed toImg, Photowould be the table name.
So I tried to switch the code into another method which is:
Dim source As String = "Data Source=LAPTOP-85ALBAVS\SQLEXPRESS;Initial Catalog=Portal;Integrated Security=True"
Dim con As New SqlConnection(source)
Dim command As New SqlCommand("Insert into Photo (Img, Pname) Values (#Img, #Pname)", con)
Dim ms As New MemoryStream
pictureBox1.Image.Save(ms, pictureBox1.Image.RawFormat)
command.Parameters.Add("#Img", SqlDbType.Image).Value = ms.ToArray()
command.Parameters.Add("#Pname", SqlDbType.VarChar).Value = TextBox2.Text
con.Open()
If command.ExecuteNonQuery() = 1 Then
MessageBox.Show("Successfully uploaded", "Message", MessageBoxButtons.OK)
Else
MessageBox.Show("Failed. Try again.", "Message", MessageBoxButtons.OK)
End If
So it's actually worked I guess. Not sure if there would be any hidden error. Any comment would be helpful guys. This is the output of Photo table.
Phototable output
This error occurs when you specify a the size of a parameter and then provide data that is larger than that. For a start, the way you're adding the parameter is bad:
qry.Parameters.Add(New SqlParameter("#images", images))
You're not specifying a data type or a size there so you're relying on the system default type being OK. Obviously it is not or you would not be getting this error. ALWAYS specify the data type and, if the data type is variable-size, the size as well, e.g.
qry.Parameters.Add("#images", SqlDbType.VarBinary, 8000).Value = images
The SqlDbType value you specify should match the data type of the column the data is for and the size should match the size in the database too. If you use varbinary(max) in the database then use -1 for the parameter size.
First, you should know that IMAGE data type usage is deprecated. Usage of VARBINARY(MAX) is more recommended:
ALTER TABLE TableName ALTER COLUMN Photo VARBINARY(MAX)
The explanation about image data type deprecation can be seen here.
For storing images you have to make use of the varbinary(MAX)
datatype. The image datatype will be deprecated.
Next, the exception occurred because you're adding data to image column which has smaller size than passed image from parameter (because SqlDbType is not specified, CLR infers Byte(n) type automatically; hence data truncation may occur to fit passed array for IMAGE data type). Use SqlDbType.VarBinary with size set to -1:
qry.Parameters.Add("#images", SqlDbType.VarBinary, -1).Value = images
Note that you can set maximum size of VARBINARY with certain numbers in bytes (other than -1), but you need to check against images.Length to prevent truncation (simply cancel upload process if image size is larger than specified).
If images.Length > 1048576 Then ' maximum limit e.g. 1 MiB
' cancel upload
Else
' continue and save to DB
End If
Finally, adjust the query to use parameters for all values:
Dim source As String = "Data Source=LAPTOP-85ALBAVS\SQLEXPRESS;Initial Catalog=Portal;Integrated Security=True"
Using con As New SqlConnection(source)
con.Open()
Dim cmd As String = "Insert into Photo Values(#pname, #images)"
Using qry As New SqlCommand(cmd, con)
qry.Parameters.Add("#pname", SqlDbType.NVarchar, 50).Value = TextBox2.Text
qry.Parameters.Add("#images", SqlDbType.VarBinary, -1).Value = images
Dim i As Integer = qry.ExecuteNonQuery()
' other stuff
End Using
End Using
When I try to update my databse table, what should I do?
Why am I getting this error?
it's because mismatched datatype inserted to your columns
change update query to be like this
update Hasil_Rml_Hallo_Bro SET Nilai_Error=" & Label3.text & " WHERE ID=" & label4.text
remove the "'" apostrophe letter
Make sure that your column in your database has the same data type which you are inserting into it.
Always use Parameters
Dim query As String = "update Hasil_Rml_Hallo_Bro SET Nilai_Error= #Error WHERE ID=#Id"
Using connection As New OleDbConnection(connectionString)
Using command As New OleDbCommand(query, connection)
Dim errorParameter As New OleDbParameter With
{
.ParameterName = "#Error",
.OleDbType = OleDbType.VarChar, // Or what is correct type in database
.Value = Label3.text
}
Dim idParameter As New OleDbParameter With
{
.ParameterName = "#Id",
.OleDbType = OleDbType.Integer, // Or what is correct type in database
.Value = Integer.Parse(label4.text) // Convert to correct type if needed
}
command.Parameters.Add(errorParameter, idParameter)
connection.Open()
command.ExecuteNonQuery()
End Using
End Using
Notice that you need put correct type for the parameter - same as column type you are using.
I am using the following SQL statement :
Dim strSql5 As String = "SELECT * FROM dbo.ontledings " & _
" where plaasblok = #plaasblokparsversoeke " & _
" and analisedatum = #laastedatum"
cnn.Open()
Dim aksie2 As New SqlClient.SqlCommand(strSql5, cnn)
aksie2.Parameters.Add("#plaasblokparsversoeke", SqlDbType.VarChar).Value = plaasblokparsversoeke
aksie2.Parameters.Add("#laastedatum", SqlDbType.Date).Value = laastedatum
aksie2.ExecuteNonQuery()
cnn.Close()
I want to fill a datatable like so :
Dim dtb5 As New DataTable
dtb5.Clear()
Using cnn As New SqlConnection("Data Source=GIDEON-E-LAPTOP\SQLEXPRESS2014;Initial Catalog=SkeduleringDatabasis;Integrated Security=True")
cnn.Open()
Using dad5 As New SqlDataAdapter(strSql5, cnn)
dad5.Fill(dtb5)
End Using
cnn.Close()
End Using
I get the following error message : Must declare the scalar variable "#plaasblokparsversoeke"
I cannot figure out where and how to declare the scalar variables.
The error occurs at the line : dad5.Fill(dtb5)
Regards
You need to add the parameters like
cmd.Parameters.Clear()
cmd.Parameters.AddWithValue("#plaasblokparsversoeke", plaasblokparsversoeke.Text)
cmd.Parameters.AddWithValue("#laastedatum", laastedatum.Text)
As correctly commented below, you need to use the Add method to add the paramters:
cmd.Parameters.Add("#plaasblokparsversoeke", SqlDbType.Varchar).Value = plaasblokparsversoekeVariable;
cmd.Parameters.Add("#laastedatum", SqlDbType.Varchar).Value = laastedatumVariable;
Firstly, avoid hard-coding a parameterised query in this way, for avoidance of SQL injection.
To answer your specific question: you are trying to use parameters in the query without having defined them in the SQLCommand.
Have a look at MSDN for the full documentation.
With this query
Dim strSql5 As String = "SELECT * FROM dbo.ontledings " & _
" where plaasblok = #plaasblokparsversoeke " & _
" and analisedatum = #laastedatum"
You are definining 2 SQL variables called #plaasblokparsversoeke and #laastedatum that you have to pass as parameters to your command, like this
command.Parameters.Add("#plaasblokparsversoeke", SqlDbType.Int);
command.Parameters["#plaasblokparsversoeke "].Value = yourValue;
MSDN article on SQL command parameters here
Is there a way to use DateTimePicker as your searching device for ListView?
I don't know how to use DateTimePicker as my search engine...
HERE IS THE CODES FOR MY SEARCH:
Dim conn As SqlConnection
Dim cmd As SqlCommand
Dim da As SqlDataAdapter
Dim ds As DataSet
Dim itemcoll(100) As String
Me.ListView1.View = View.Details
Me.ListView1.GridLines = True
ListView1.Items.Clear()
conn = New SqlConnection("Data Source=#####;Initial Catalog=#####;Persist Security Info=True;User ID=#####;Password=#####")
Dim strQ As String = String.Empty
strQ = "SELECT ControlNo,EmpNo,CheckOutDate,CheckOutTime,TaxiNo,PlateNo,Model,Make FROM dbo.ChkInOut WHERE ControlNo ='" + txtsearch.Text + "'"
cmd = New SqlCommand(strQ, conn)
da = New SqlDataAdapter(cmd)
ds = New DataSet
da.Fill(ds, "Table")
Dim i As Integer = 0
Dim j As Integer = 0
For i = 0 To ds.Tables(0).Rows.Count - 1
For j = 0 To ds.Tables(0).Columns.Count - 1
itemcoll(j) = ds.Tables(0).Rows(i)(j).ToString()
Next
Dim lvi As New ListViewItem(itemcoll)
Me.ListView1.Items.Add(lvi)
Next
There are few problems with your code as is, so let's take them one at a time
SqlCommand inherits from DbCommand, which implements the IDisposable interface.
The primary use of this interface is to release unmanaged resources.
The best way do that is with the Using keyword. For a code example of that, take a look at the sample code at the bottom of this page.
Same goes for SqlConnection, wrap it in a Using statement.
Don't concatenate strings together to make SQL queries, this opens your application up to SQL Injection attacks. There are examples of how to create parameterized queries here and here (unfortunately I didn't see a good example on MSDN).
In your case, the query will look like this:
strQ = "SELECT ControlNo, ..<rest of columns>.. ,Model,Make " & _
"FROM dbo.ChkInOut " & _
"WHERE ControlNo = #controlNo"
cmd = New SqlCommand(strQ, conn)
cmd.Parameters.AddWidthValue("#controlNo", txtsearch.Text);
... rest of code here ...
To query by a user specified date, you need to first get the date from the DateTimePicker.Value property. Then construct a query (like in the example above) and pass a parameter with the selected date. You may find this question abou SQL Server dates helpful.
I've written a console app in VB.NET to do some database work and a strange runtime error has arisen...
Here's the main code:
Sub Main(ByVal args() As String)
Try
user = args(0)
batchID = args(1)
GetBatchRevision()
'batchRev = 1
Dim getTestScripts As SqlCommand = New SqlCommand("GetTestScriptsInTestBatch", cs)
getTestScripts.CommandType = CommandType.StoredProcedure
Dim batchIDParam As SqlParameter = getTestScripts.Parameters.Add("#batchID", SqlDbType.Int, 4)
Dim batchRevParam As SqlParameter = getTestScripts.Parameters.Add("#batchRev", SqlDbType.Int, 4)
'batchIDParam.Value = 1
'batchRevParam.Value = 1
batchIDParam.Value = batchID
batchRevParam.Value = batchRev
Console.WriteLine(batchID & " " & batchRev)
Console.WriteLine(cs.State)
Console.ReadLine()
Using cs
cs.Open()
Dim reader As SqlDataReader = getTestScripts.ExecuteReader(CommandBehavior.CloseConnection)
While reader.Read()
Console.WriteLine("Executing Test Script " & reader("ScriptID").ToString() & " Revision " & reader("ScriptRev").ToString)
End While
Console.ReadLine()
End Using
Catch ex As Exception
End Try
End Sub
GetBatchRevision:
Private Sub GetBatchRevision()
Using cs
Dim GetNewestRev As New SqlCommand("SELECT Max(BatchRev) FROM TestBatch WHERE BatchID=" & batchID, cs)
cs.Open()
Dim reader As SqlDataReader = GetNewestRev.ExecuteReader(CommandBehavior.CloseConnection)
reader.Read()
If Not IsDBNull(reader(0)) Then
batchRev = reader(0).ToString()
End If
End Using
End Sub
batchRev and batchID are both global variables within the module.
Behaviorally:
The app prints out "1" (user input), "1" (database result), "0" (enum of Closed connection)
When I press Enter to get past the first Console.ReadLine(), the app simply closes out.
If I comment out GetBatchRevision and directly set batchRev = 1, I get the above result as well as "Executing Test Script 1 Revision 52", "Executing Test Script 2 Revision 66" which are the expected results from the stored procedure GetTestScriptsInTestBatch.
The global variable declarations are as follows:
Private batchID As String
Private batchRev As String
Any ideas why GetBatchRevision() causes the app to crash? By itself (removing the stored proc part of the code), it executes just fine. My initial guess was that there was a hanging connection, but ending a "using" block is supposed to close a SQL connection as well as any open readers associated with said connection (as mentioned before, cs.State returns 0).
Your problem is on these lines:
reader.Read()
If Not IsDBNull(reader(0)) Then
reader.Read() is probably returning false; yet you try to access reader(0). Boom!
You should change it to:
IF reader.Read() AndAlso Not IsDBNull(reader(0)) Then
'' etc
End If
It looks like cs is also a global variable. This is a bad idea. .Net data access works a lot better when you're using a new connection each time. You're probably fine in this app, but you're setting up some bad habits. Instead, load your connection string as a global variable and use that when creating your connections.
Next up, there's no reason for GetBatchRevision() to talk to global variables. Have it accept an argument and return it's result instead. And of course I can't overlook the sql injection issue because you concatentate the batchid to the end of your string. Here's the new version of the function after fixing those errors:
Private Function GetBatchRevision(ByVal BatchID As String) As String
Using cn As New SqlConnection(cs), _
GetNewestRev As New SqlCommand("SELECT Max(BatchRev) FROM TestBatch WHERE BatchID= #BatchID", cn)
GetNewestRev.Parameters.Add("#Batch", SqlDbType.Int).Value = Convert.ToInt32(BatchId)
cn.Open()
Return GetNewestRev.ExecuteScalar().ToString()
End Using
End Function
This can get even better if you keep BatchRev and BatchID as int's rather than strings internally.