Parameterized Update Query for Sql server in ASP.net with VB - asp.net

I am trying to write a paramaterized update query to insert values into an Sql Server Express Database. The query I have written is:
Dim cmd As New SqlCommand
cmd.Connection = conn
cmd.CommandText = "update tblposts set title=#ptitle, pdate=#pd,
content=#pcontent where pid=#p"
cmd.Parameters.AddWithValue("ptitle", txtTitle.Text)
cmd.Parameters.AddWithValue("pcontent", txtcontent.InnerText)
cmd.Parameters.AddWithValue("pd", DateTime.Now.ToString)
cmd.Parameters.AddWithValue("p", postid)
On running cmd.ExecuteNonQuery, I get number of rows affected as 1, but the change is not reflected in the database.
On printing the query using Debug.Write, I get the query not with the parameter values, but the names of the parameters itself (ie. #pcontent, #title etc)
What can be the mistake here?

In you're AddWithValue you need to include the # symbol on the front of the parameter, so:
cmd.Parameters.AddWithValue("#ptitle", txtTitle.Text)
cmd.Parameters.AddWithValue("#pcontent", txtcontent.InnerText)
cmd.Parameters.AddWithValue("#pd", DateTime.Now.ToString)
cmd.Parameters.AddWithValue("#p", postid)
I'm guessing that it's executing correctly but there where clause is blank, so perhaps updating a blank row.
Anyway, try the above and it should update as expected.
Edit to Add
The CommandText will always only have the #value in there, it will not substitue the parameter values into the string.
You would need to loop through the cmd.Parameters collection to write out the values.

Related

Stored Procedure Not Working From ASP Page

we are having issues with a stored procedure. When calling it from our website via asp/vb.net it seems to not be executing properly. If I run it from SSMS it works.
I have run the debugger when the call is being placed, the parameters being passed in are correct at the time of the ExecuteNonQuery() call but it is not generating any records in the related tables like it should. If I use the same values seen while debugging our website directly in SSMS, the stored procedure creates the expected records.
Here is our stored procedure:
ALTER PROCEDURE [dbo].[CopyGoals](
#OldVisitID int,
#NewVisitID int,
#CreatedBy NVarChar(30)
) AS BEGIN
declare #GoalMapping As Table(OldGoalID int,NewGoalID int);
Merge Into VisitGoals
Using(
select GoalsID,Goal,ProgressNote,Progress,Completed,CreatedOn,CreatedBy,VisitID
From VisitGoals
Where VisitID = #OldVisitID
) As Src
On 1 = 0
When Not Matched By Target Then
Insert (Goal,ProgressNote,Completed,VisitID,Progress, CreatedOn, CreatedBy)
Values (Src.Goal, Src.ProgressNote, Src.Completed, #NewVisitID, Src.Progress, GetDate(), #CreatedBy)
Output Src.GoalsID As OldGoalID, inserted.GoalsID as NewGoalID
Into #GoalMapping;
Insert Into SubGoals(GoalID,VisitID,GoalText,HasCompleted,WillComplete,GoalStatus)
(
Select GM.NewGoalID, #NewVisitID, SG.GoalText, SG.HasCompleted, SG.WillComplete, SG.GoalStatus
From SubGoals As SG inner join #GoalMapping As GM on SG.GoalID = GM.OldGoalID
Where SG.VisitID = #OldVisitID
)
END
Here is the procedure call from our website page:
Dim conStr As String = ConfigurationManager.ConnectionStrings("ConnectionString").ConnectionString
Dim curUsr As New Supervisor(Context.User.Identity.Name, True)
Using con As New SqlConnection(conStr)
Using cmd As New SqlCommand("CopyGoals", con)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Add("#OldVisitID", SqlDbType.Int).Value = oldVID
cmd.Parameters.Add("#NewVisitID", SqlDbType.Int).Value = newVID
cmd.Parameters.Add("#CreatedBy", SqlDbType.NVarChar, 30).Value = curUsr.Name
con.Open()
cmd.ExecuteNonQuery()
con.Close()
End Using
End Using
What this procedure should do, and does if run from SSMS, is look at our Goals table with the existing IDs matching a foreign key corresponding to the VisitID in a different table to find all goals associated with that old visit.
It them copies the goal information and inserts it into the Goals table, outputting the old goal IDs and the newly inserted goal IDs into the #GoalMapping table.
It then looks into our SubGoals table and does a similar thing by copying each subgoal related to the goals we just copied. For whatever reason, this procedure does not execute properly when called from our page even when it runs in SSMS when we feed it the same input values as seen during debugging of the page. There are no errors reported in chrome's debugger, we tried wrapping execute in a try with an SQL and normal exception but neither of them tripped. We are pretty stumped. Maybe someone will spot something we haven't over the last few days.
Here is the output from Sql Profiler:
Okay, I finally figured it out. There was a permission issue as Mohsin suggested. I logged in as the user that we use for our ASP.net connection strings and attempted to run the query in question and it failed to generate the records from SSMS. So after some digging I found this question:
Stored Procedure and Permissions - Is EXECUTE enough?
Which lead to this question when I got the same error:
SQL Server principal "dbo" does not exist,
Combined together, the answers to these questions helped me fix the issue.

How to query from a database in ASP.NET?

I'm still somewhat new to ASP.NET and VB, and I found out that it's vastly different from the ASP I learned where I used Recordset to extract data from the database. Can someone give me some pointers on how to extract data from a database? Here is what I used to at least connect:
Dim conn As OdbcConnection
conn = New OdbcConnection("DSN=southwind")
Dim mystring as String = "SELECT GroupName FROM Group"
Dim cmd As OdbcCommand = New OdbcCommand(mystring, conn)
conn.Open()
Dim reader As OdbcDataReader = cmd.ExecuteReader()
The last line gives me an error saying:
Exception Details: System.Data.Odbc.OdbcException: ERROR [42000] [Microsoft][SQL Server Native Client 11.0][SQL Server]Incorrect syntax near the keyword 'Group'.
But since I don't quite understand ASP.NET completely, not too sure what it means even though the syntax looks fine. Removing that line runs the code just fine. How would I display all the contents from the GroupName column in table Group?
EDIT: Thanks everyone, I completely forgot that Group was reserved in SQL.
Group is a keyword in SQL, you need to wrap it in square brackets like this,
SELECT GroupName FROM [Group]
This would assume the Group to be a name of the table, instead of a key word; of GROUP BY clause.
Group is a keyword in SQL. If your table name or column names referenced in your query are keywords, you can enclose them in brackets.
Dim mystring as String = "SELECT GroupName FROM [Group]"

about SQLite query

I'm using SQLite & in that i'm using the following query-
INSERT INTO Contact(FirstName, LastName, MobileNumber, IsArchive) VALUES('mina', 'Ambani', '9874587458', 1); SELECT last_insert_rowid() AS 'Identity';
this query insert the record & also gives last insert row id of identity column in my table but initially it generates error as-
The following errors were encountered while parsing the contents of the SQL pane:
Unable to parse query text
How to remove this error?
thanks.
Sqlite does not seem to support multiple SQL statements in one query. Run a separate subsequent query. Something like
SQLiteCommand IDCmd = new SQLiteCommand("Select last_insert_rowid();", conn);
cmd.ExecuteNonQuery(); // EXECUTE INSERT HERE
long id = (long)IDCmd.ExecuteScalar();
Connection open/close and error handling is missing from this example.

How to check a SQL database table to see if a record exists

I have a SQL database that creates a record for every document uploaded by the user to the server. I want to check this table before a user uploads a document to ensure they don't upload a file with name that already exists.
I know how to make the connection and make the SqlCommand to query the table for an existing record. But I don't know how to check the record count from the sqlCommand I made.
Does that make sense?
Using myConnectionCheck As New SqlConnection(myConnectionStringCheck)
Dim myCommandCheck As New SqlCommand()
myCommandCheck.Connection = myConnectionCheck
myCommandCheck.CommandText = "SELECT * FROM Req_Docs WHERE Doc_Name =" & DocName
myConnectionCheck.Open()
myCommandCheck.ExecuteNonQuery()
End Using
Thanks in advance,
Anthony
use if exists for this issue
create procedure isDocExists
#DocName varchar(255),
#isExists bit output
as
set #isExists = 0
if exists (SELECT Doc_Name FROM Req_Docs WHERE Doc_Name =#DocName)
begin
set #isExists=1
end
to check where record is there or not
So many things wrong here:
Race condition between when you check and when you upload
Multiple Documents should legitimately be allowed to have the same name. Use tags, folders, timestamps, or other means to distinguish them.
Sql Injection vulnerability on the name parameter
ExecuteNonQuery() on a SELECT query.
I'll give you the benefit of the doubt on the first two points that you're still gonna allow the upload, and this is just so you can ask the user how they want to relate the documents. Given that, here's how you fix the other two:
Using cn As New SqlConnection(myConnectionStringCheck), _
cmd As New SqlCommand("SELECT COUNT(*) FROM (SELECT TOP 1 1 FROM Req_Docs WHERE Doc_Name= #DocName) t", cn)
cmd.Parameters.Add("#DocName", SqlDbTypes.VarChar, 255).Value = DocName
cn.Open()
Return CInt(cmd.ExecuteScalar())
End Using
ExecuteNonQuery is a function, that returns an integer equal to the number of rows affected by the query.
However, it's usually used for updates.
You might consider ExecuteScalar, which returns the first column of the first row in the result set.
So if you change the query to select count(*) from..., the result of ExecuteScalar will be the number of rows, which you can then test.
if you want count:
SELECT COUNT(*) as count FROM Req_Docs WHERE Doc_Name = 'DocName'

Integer variable is acquiring a string value of "ad" somewhere along the line, can anyone see where?

Here is my code:
I should get output of the department id (did) as an integer and the templatefilename (result) that is required.
The errors I get are: Conversion from string "ad" to type 'Integer' is not valid. I'm fairly new to asp.net and cannot see where the did variable picks up the "ad" string.
Any help would be greatly appreciated.
Thanks
When you construct the query to the table departmentsgroupings, you're changing the value of sql, but you aren't creating a new SqlCommand. This means that cmd still contains the old SQL statement (the query to the Modules table) which, when executed, returns "ad".
To fix this, change your code as follows:
sql = ("select departmentsid from departmentsgroupings where groupingid =" & pageid & "")
Set cmd = New SqlCommand(sql, conn)
did = (cmd.ExecuteScalar)
You may have expected the change you made to sql to get passed on automatically to the SqlCommand -- but it doesn't work that way.
Edit: Your code, as written, is vulnerable to SQL injection attacks. If you don't know what these are, you need to read the first answer to this:
How does the SQL injection from the "Bobby Tables" XKCD comic work?
To protect yourself against these kinds of attacks, use parameterized queries.
The mistake is in these lines:
sql = ("select departmentsid from departmentsgroupings where groupingid =" & pageid & "")
did = (cmd.ExecuteScalar) <---- Wrong command executed here.
You presumably meant to execute the code in sql, not cmd again.

Resources