SQL parameters asp.net(vb.net) - asp.net

Sorry for my bad English.I have a problem in my code:
Dim sq As String = "SELECT username FROM standing WHERE username = #user"
Dim con As New SqlConnection(Sql.ConnectionString)
Dim cmd As New SqlCommand(sq, con)
cmd.Parameters.Add("#user", SqlDbType.VarChar)
cmd.Parameters("#user").Value = "contesttest"
con.Open()
Dim index As Integer = cmd.ExecuteNonQuery
con.Close()
If (index > 0) Then
'Something..
Else
'Something else..
End If
in my code,"contesttest" is exists in Database and returnedrows(index) should be greater than 0.But index is -1 !What's the problem?
my connectionstring is right.
It does not matter if C# or VB.Net

If your username field is an unique index (meaning that you don't have two username with the same value) then your query could be rewritten without using a SqlDataReader
Dim sq As String = "SELECT username FROM standing WHERE username = #user"
Using con SqlConnection(Sql.ConnectionString)
Using cmd As New SqlCommand(sq, con)
cmd.Parameters.Add("#user", SqlDbType.VarChar)
cmd.Parameters("#user").Value = "contesttest"
con.Open()
Dim username = cmd.ExecuteScalar
If userName IsNot Nothing Then
'Something..
Else
'Something else..
End If
End Using
End Using
ExecuteScalar return the first column of the first row retrieved by your command. In the case you column is a unique index/primary key then you have just one row and you return just the username. So if there is something returned then you have found your user

From MSDN;
For UPDATE, INSERT, and DELETE statements, the return value is the
number of rows affected by the command. When a trigger exists on a
table being inserted or updated, the return value includes the number
of rows affected by both the insert or update operation and the number
of rows affected by the trigger or triggers. For all other types of
statements, the return value is -1. If a rollback occurs, the return
value is also -1.
This is not a problem. It is a definition of ExecuteNonQuery method.

Use a Reader of some sort (like a SqlDataReader) to get the number of rows returned from a SELECT statement or ExecuteScalar to get a single returned value. Using ExecuteNonQuery will only return the number of rows affected when used with a SELECT statement.
For UPDATE, INSERT, and DELETE statements, the return value is the
number of rows affected by the command. When a trigger exists on a
table being inserted or updated, the return value includes the number
of rows affected by both the insert or update operation and the number
of rows affected by the trigger or triggers. For all other types of
statements, the return value is -1. If a rollback occurs, the return
value is also -1.
Read about it on MSDN.

i guess SqlDbType.VarChar will allow only one character ..you need to pass length also for varchar.
for Example:-
cmd.Parameters.Add("#user", SqlDbType.VarChar,80)

Related

Retrieve the Id of recently inserted record

I currently have this SQL insert code in code behind
Dim con As New SqlConnection
Dim conString As String
conString = ConfigurationManager.ConnectionStrings("MyConnection").ConnectionString
con = New SqlConnection(conString)
con.Open()
Dim cmd As New SqlCommand("INSERT INTO AdditionalDaysRequest(Status, AdditionalDays, Justification,RequestDaySubmitted) VALUES (#Status,#AdditionalDays,#Justification,#RequestDaySubmitted)", con)
cmd.Parameters.AddWithValue("#Status", "Pending Request")
cmd.Parameters.AddWithValue("#AdditionalDays", TB_Days.Text)
cmd.Parameters.AddWithValue("#Justification", TB_Justification.Text)
cmd.Parameters.AddWithValue("#RequestDaySubmitted", Date.Now)
cmd.ExecuteNonQuery()
con.Close()
The Id in this table is automatically generated and incremented
What I would like to have now is the Id of this record inserted to add it to another table
Change your query text to add a second statement:
...;SELECT SCOPE_IDENTITY();
The SELECT SCOPE_IDENTITY() statement Returns the last identity value inserted into an identity column in the same scope as from the MSDN article above.
In addition, you can use the ability of the Sql engine to understand and process two or more command statements passed as a single string if you separe the statements with a semicolon.
In this way you have the great benefit to execute a single trip to the database.
Dim cmd As New SqlCommand("INSERT INTO AdditionalDaysRequest(Status, " & _
"AdditionalDays, Justification,RequestDaySubmitted) VALUES " & _
"(#Status,#AdditionalDays,#Justification,#RequestDaySubmitted);" & _
"SELECT SCOPE_IDENTITY()", con)
cmd.Parameters.AddWithValue("#Status", "Pending Request")
cmd.Parameters.AddWithValue("#AdditionalDays", TB_Days.Text)
cmd.Parameters.AddWithValue("#Justification", TB_Justification.Text)
cmd.Parameters.AddWithValue("#RequestDaySubmitted", Date.Now)
Dim result = cmd.ExecuteScalar()
con.Close()
if result IsNot Nothing Then
Dim lastInsertId = Convert.ToInt32(result)
End If
Notice that the two statements are now executed using ExecuteScalar instead of ExecuteNonQuery because we want to catch the result of the last command.
You will want to run a new SqlCommand. Set the value of lastInsertId with this statement:
SELECT SCOPE_IDENTITY()
This would be an additional knowledge.
we have multiple options like:
##IDENTITY
SCOPE_IDENTITY
IDENT_CURRENT
All three functions return last-generated identity values. However
IDENT_CURRENT returns the last identity value generated for a specific table in any session and any scope.
##IDENTITY returns the last identity value generated for any table in the current session, across all scopes.
SCOPE_IDENTITY returns the last identity value generated for any table in the current session and the current scope.

Compare Number of Rows affected

I'm trying to compare a string (network ID) and using a SQL Like command, return the numbers of rows affected (if the user name was found or not) however in my code I'm always getting " -1 " which i can not find why, the username is correct and found in the SQL table by running a query in SQL Server Mgt.
Try
Dim Con As New SqlConnection
Con.ConnectionString = "Data Source=WCRDUSMJEMPR9\SQLEXPRESS;Initial Catalog=MicroDB;Integrated Security=True"
Con.Open()
Dim SQL2 As String
SQL2 = "SELECT * from MicroDB_Users WHERE Users LIKE '+#Usercheck+'"
Dim cmd2 As New SqlCommand(SQL2, Con)
cmd2.Parameters.AddWithValue("#Usercheck", TextBox1.Text)
Dim obj2 = cmd2.ExecuteNonQuery
Con.Close()
If obj2 > 0 Then
MsgBox(obj2)
Response.Redirect("~\ControlCharts\AddData_Control.aspx")
Label7_Control.Visible = False
Else
MsgBox(obj2)
Label7_Control.Text = ("You are not authorized to Add Data")
Label7_Control.Visible = True
End If
Catch ex As Exception
MsgBox(Err.Description)
As you can see, i;m using a IF to compare if the user was found ( 1 row affected) or if it was not found ( 0 rows affected).
ExecuteNonQuery is used for insert,update or delete queries only. So you either have to use COUNT in your query and use ExecuteScalar or use ExecuteReader and the reader's HasRows property.
Using var reader = cmd2.ExecuteReader()
If reader.HasRows Then
' ...
Else
' ...
End If
End Using
ExecuteNonQuery:
For UPDATE, INSERT, and DELETE statements, the return value is the
number of rows affected by the command. When a trigger exists on a
table being inserted or updated, the return value includes the number
of rows affected by both the insert or update operation and the number
of rows affected by the trigger or triggers. For all other types of
statements, the return value is -1. If a rollback occurs, the return
value is also -1.
Update: Apart from that you're using the LIKE operator and the parameter incorrectly. Instead of
SQL2 = "SELECT * from MicroDB_Users WHERE Users LIKE '+#Usercheck+'"
cmd2.Parameters.AddWithValue("#Usercheck", TextBox1.Text)
use this approach
SQL2 = "SELECT * from MicroDB_Users WHERE Users LIKE #Usercheck"
cmd2.Parameters.AddWithValue("#Usercheck", string.Format("%{0}%", TextBox1.Text))
The number of rows affected is only returned when you do INSERT, DELETE, and UPDATE.
ExecuteNonQuery
For UPDATE, INSERT, and DELETE statements, the return value is the
number of rows affected by the command. When a trigger exists on a
table being inserted or updated, the return value includes the number
of rows affected by both the insert or update operation and the number
of rows affected by the trigger or triggers. For all other types of
statements, the return value is -1. If a rollback occurs, the return
value is also -1.
To get the number of rows, use SELECT count(*) FROM myTable
ExecuteNonQuery is meant for query that does not return rows, obvious from its name NonQuery.
For query that returns result, use these instead
ExecuteReader() - when multiple rows are returned
ExecuteScalar() - when one row and one column is returned. This will be perfect in your case
The number of rows is affected when you write INSERT UPDATE and DELETE scripts, not SELECT .. Use SQL2 = "SELECT * from MicroDB_Users WHERE Users LIKE '+#Usercheck+'" instead and cmd2.ExecuteScalar()
SQL2 = "SELECT COUNT(*) from MicroDB_Users WHERE Users LIKE '%" + TextBox1.Text + "%'";
Dim cmd2 As New SqlCommand(SQL2, Con)
cmd2.Parameters.AddWithValue("#Usercheck", TextBox1.Text)
Dim obj2 As Int32 = 0
obj2 = Convert.ToInt32(cmd2.ExecuteScalar())

checking for duplicate values before attempting insert (ASP.NET)

I have a form where two fields on the first page of the form make up the primary key. I want to check for duplicate values before attempting to insert the record, since I don't want the user to go all the way through the form only to find out they can't submit it. So I'm trying to check for duplicate values when the user tries to go to the next page of the form. I wasn't quite sure how to do it, and sure enough I'm getting an error. ("Object reference not set to an instance of an object.") The problem is apparently in my if statement, "If myValue.Length > 0 Then", but I'm not sure what needs to be in place of that.
Protected Sub CustomValidator1_ServerValidate(ByVal source As Object, ByVal args As System.Web.UI.WebControls.ServerValidateEventArgs) Handles CustomValidator1.ServerValidate
'get values
Dim checkPrefix = txtCoursePrefix.Text
Dim checkNum = txtCourseNum.Text
'db connectivity
Dim myConn As New OleDbConnection
myConn.ConnectionString = AccessDataSource1.ConnectionString
myConn.Open()
'select records
Dim mySelect As New OleDbCommand("SELECT prefix, course_number FROM tableCourse WHERE prefix='checkPrefix' AND course_number='checkNum'", myConn)
'execute(Command)
Dim myValue As String = mySelect.ExecuteScalar()
'check if record exists
If myValue.Length > 0 Then
CustomValidator1.ErrorMessage = "some exp text"
CustomValidator1.SetFocusOnError = "true"
CustomValidator1.IsValid = "false"
End If
End Sub
Thought I'd post the final solution:
'select records
Dim mySelect As New OleDbCommand("SELECT 1 FROM tableCourse WHERE prefix=? AND course_number=?", myConn)
mySelect.Parameters.AddWithValue("#checkPrefix", checkPrefix)
mySelect.Parameters.AddWithValue("#checkNum", checkNum)
'execute(Command)
Dim myValue = mySelect.ExecuteScalar()
'check if record exists
If myValue IsNot Nothing Then
CustomValidator1.SetFocusOnError = True
args.IsValid = False
End If
This error indicates that the content of myValue variable is null. If it's null you can't use Length property (or any other property for that matter) on it. You have to check for null explicitly:
If myValue IsNot Nothing Then
EDIT 1
Your sql query is wrong. I don't know what would be the right query, as I don't know your database, but I think you intender to write this:
Dim mySelect As New OleDbCommand("SELECT prefix, course_number FROM tableCourse WHERE prefix=" + checfkPreix + " AND course_number=" + checkNum, myConn)
or something to that effect. You might want to consider using string.Format function for forming the string. And you also need to make sure that there is some kind of protection against SQL Injection, since you form your query from user input. In your case using of OleDbParameter might be appropriate.
Edit 2
You also right to mention that there might be a problem with ExecuteScalar. ExecuteScalar is supposed to return a single value and your select query are returning two (prefix and course_number). Change it so that it returns a single parameter SELECT prefix FROM or simply SELECT 1 FROM and then the rest of the query:
Dim mySelect As New OleDbCommand("SELECT 1 FROM tableCourse WHERE prefix=? AND course_number=?", myConn)
mySelect.Parameters.AddWithValue("#checkPrefix", checkPrefix)
mySelect.Parameters.AddWithValue("#checkNum", checkNum)
Edit 3
You are not setting failed validation properly in your validator.
Add
args.IsValid = False
inside your if statement.
First ExecuteScalar will only return a single value, so in this case you are only going to get the column prefix from the result. Second if there is no match with your query it will return null, so your next length check should account for that scenario:
if String.IsNullOrEmpty(myValue) Then
...
Reference: http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.executescalar.aspx
myValue is null if there is no duplicate, so you have to apply .Length only if myValue is not null (which means checking for null only is enough; without .Length)
If Not string.IsNullOrEmpty(myValue) Then
try something like this instead (you will have to adapt it to VB.Net) DBNull is different from Null or Nothing so you have to compare it to both
If myValue <> DBNull and not myvalue is nothing Then

Executenonquery return value

I want to perform a search on a table to see if record exists. I do not want to perform insert or update after. I have done this already but somehow I cannot get this to work. On my asp.net page I cannot seem to get any value returned. The error is "input string not in correct format" I ma sure it is obvious but I cannot seem to see it now!
here is my code:
Dim con As New SqlConnection("connstring")
Dim cmd As New SqlCommand("checkname", con)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Add(New SqlParameter("#d", SqlDbType.Int))
cmd.Parameters("#id").Value = TextBox1.Text
Dim para As New SqlParameter
para.Direction = ParameterDirection.ReturnValue
para.ParameterName = "returnvalue"
cmd.Parameters.Add(para)
con.Open()
cmd.ExecuteNonQuery()
Dim exists As Integer
exists = Convert.ToInt32(cmd.Parameters("returnvalue").Value)
If exists = 1 Then
Label1.Text = "You......"
ElseIf exists = 0 Then
Label1.Text = "You....."
End If
con.Close()
stored procedure:
CREATE PROCEDURE checkname
-- Add the parameters for the stored procedure here
#id int
AS
--This means it exists, return it to ASP and tell us
-- SELECT 'already exists'
IF EXISTS(SELECT * FROM attendees WHERE id = #id)
BEGIN
RETURN 1
END
ELSE
BEGIN
RETURN 0
END
You need to ensure that you are passing an integer.
int intValue;
if(!int.TryParse(TextBox1.Text, out intValue))
{
// Update your page to indicate an error
return;
}
cmd.Parameters.Add(New SqlParameter("id", SqlDbType.Int));
cmd.Parameters("id").Value = intValue;
(Technically you don't need the "#" character when
defining the parameters in the .NET
code.)
You have declared your procedure parameter as #d instead of #id. Also a return parameter cannot be an input parameter. The return value should be an exit code. You most likely want to create an output parameter and set that to 1 or zero inside of your stored procedure.
Edit: to clarify, the return value is generally regarded as an indicator of correct execution. Zero usually means success, where any other numeric value is generally regarded as an error code. That is why I recommended adding an output parameter instead of adding a return value parameter.
ExecuteNonQuery returns the number of rows affected. Therefore the return values that you set in your stored procedure are thrown away and will not be returned by the ExecuteNonQuery method.
ExecuteNonQuery is used to Insert / Delete / Update operations. Not for SELECT, you need either ExecuteScalar or ExecuteReader methods. This link will help you to know how to use output parameters : http://aspdotnet-suresh.blogspot.com/2010/10/introduction-here-i-will-explain-how-to.html

IF EXISTS IN STORED PROCEDURE

I am using following storedprocedure
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
Alter PROCEDURE [dbo].[GetUserDetailsByUserID]
(
#UserId varchar(100)
)
AS
BEGIN
IF EXISTS(Select * from Registration where UserId=#UserID)
BEGIN
Select
[Name],
[UserId],
[PermanentAddress],
[TemporaryAddress],
[OfficePhoneNo],
[ResidentialPhoneNo],
[MobileNo],
[Email],
[ContactPerson],
[C_OfficePhoneNo],
[C_ResidentialPhoneNo],
[C_MobileNo],
[C_Email],
[Project],
[TotalAmount]
From
Registration
Where
UserId=#UserId
END
END
I am using following code in vb
Public Function GetUserDetailsByUserID(ByVal strUserId As String) As DataTable
Try
Dim db As Database = DatabaseFactory.CreateDatabase()
Dim DbCommand As DbCommand = _
db.GetStoredProcCommand("GetUserDetailsByUserID")
db.AddInParameter(DbCommand, "#UserId", DbType.String, strUserId)
Return db.ExecuteDataSet(DbCommand).Tables(0)
Catch ex As Exception
Return New DataTable()
End Try
End Function
If details corresponding to userid does not exist in registration table, db.ExecuteDataSet(DbCommand).Tables(0) shows one error as cannot find Table(0). What modification in stoted procedure i hve to make to get rid of this error?
You can simply get rid of the IF EXISTS. When the record doesn't exist, you will get an empty table (which I think is what you want, looking at your sample code)
The procedure will not always return a record set. If there is no record set then Tables will be empty and Tables(0) will fail and return an error. You should just return the selection rather than only selecting if the record exists. Your code can then check for an empty returned record set.
In the VB code, change
Return db.ExecuteDataSet(DbCommand).Tables(0)
to
Dim Ds as DataSet = db.ExecuteDataSet(DbCommand)
If Ds.Tables.Count = 1 Then
Return Ds.Tables(0)
Else
Return New DataTable()
End If
Also, remove the If Exists from the Stored Procedure, since if the row exists, you will force the database to search twice in the table for the record where UserId=#UserID.

Resources