ASP Classic to VB.NET - Recursive Function including RecordSets - asp.net

I'm hoping someone can help me think this one out because I'm stuck.
We are slowly migrating a ASP Classic web site to a .NET web application. I stumbled upon the following function. The function will return an array of strings that consists of hml a-tags.
Private Function getFullPathLinks(lNodeId, sPath, sDocTemplate)
Dim sql, recordSet, rsTmp
Dim arrPath, sResult
Dim lDocId
lDocId = getDocumentId(lNodeId)
sql = "SELECT parent_id, label FROM wt_node WHERE (node_id = " & lNodeId & ")"
Set recordSet = execSqlCache(oConn,sql,Array(),Array("wt_node"))
If Not (recordSet.Bof And recordSet.Eof) Then
If sDocTemplate <> "" Then
sPath = sPath & "|" & "<a href='" & sDocTemplate & "?nodeid=" & lNodeId & "&documentid=" & lDocId & "'>" & recordSet("label") & "</a>"
Else
sPath = sPath & "|" & recordSet("label")
End If
getFullPathLinks recordSet("parent_id"), sPath
End If
recordSet.Close
Set recordSet = Nothing
arrPath = arrReverse(Split(sPath,"|"))
sResult = Join(arrPath,sPathDelimiter)
If Right(sResult,Len(sPathDelimiter)) = sPathDelimiter Then sResult = Left(sResult,Len(sResult)-Len(sPathDelimiter))
getFullPathLinks = sResult
End Function
The function calls itself at the end and this will not work well in my .NET implementation where we are using DataReaders to talk to the SQL database.
Could I follow the same structure as above and instead use something else than a DataReader to achieve this?

I am not sure what SQL Server version you are using, but have you taken a look at recursive queries in SQL? It is designed to retrieve hierarchical data in a single db call. Take a look:
http://msdn.microsoft.com/en-us/library/ms186243(v=sql.105).aspx

Related

MS Access.adp to ASP.Net conversion: DLookup to SQL

Inherited a SQL database with an MS Access .adp front end which is being converted to ASP.net VB. Using a conversion tool which has done a good job on most of it after debugging. It however could not convert DLookup functions used in combo boxes as it is not supported. Being relativley new to .net am unclear how to convert the DLookup function to a SQL statement. The table name: dbo.Contact
The main form name: Contact_Edit
The sub form name: Contact_Edit_Sub
There are a number of combo boxes with many Dlookup functions. Once I have one I can rework the balance. Any help with converting the statement is appreciated.
The current code is listed below:
*If Not IsDBNull(Me.Contact_Edit.Contact_Edit_Sub.Intake_Worker_Code) Then
Intake_Worker_Code_Desc.Text = DLookup("[Name]", "Staff", "Code ='" & Intake_Worker_Code.SelectedValue & "'")
Else
Intake_Worker_Code_Desc.Text = ""
End If*
Try this, where [Name] is the field and Staff is the table
SELECT [Name] FROM Staff WHERE Code = '" & Intake_Worker_Code.SelectedValue & "';
Here you can read more about what DLookup does:
http://www.techonthenet.com/access/functions/domain/dlookup.php
https://support.office.com/en-us/article/DLookup-Function-8896cb03-e31f-45d1-86db-bed10dca5937
Update based on comment
VB.Net SQL code sample
If Not IsDBNull(Me.Intake_Worker_Code) Then
Dim conn_str As String = ConfigurationManager.ConnectionStrings("YourConnectionString").ConnectionString
Dim myconn As New SqlConnection(conn_str)
Dim sc As New SqlCommand()
sc.CommandText = "Select [Name] FROM [Staff] WHERE (Code = '") & (Intake_Worker_Code.SelectedValue & "')"
sc.Connection = myconn
myconn.Open()
Intake_Worker_Code_Desc.Text = sc.ExecuteScalar().ToString()
myconn.Close()
Else
Intake_Worker_Code_Desc.Text = ""
End If

second ExecuteReader() doesn't work

I have a code which checks the validity of user and then, if a user is valid it inserts certain values in the database.
My problem is when After I query my database to check if a user is valid and after that i try to pass the additional value to its account the flow stops when I invoke ExecuteReader() for the second time.
There is no error, or anything like that. I tried to substitute ExecuteReader() with ExecuteNoneQuery but still it's not working. I tried all the query in mysql command prompt they are working perfectly. I really can't understand what am I doing wrong there. Can anyone help me please?
Here is the code:
Try
myconn.Open()
Dim stquery As String = "SELECT * from accountstbl WHERE SE_ID = " & Id.Text
Dim smd = New MySqlCommand(stquery, myconn)
Dim myreader = smd.ExecuteReader()
If Not myreader.HasRows Then
errorUser.Visible = True
Else
myreader.Read()
Dim name As String = myreader.Item("user_name").ToString()
Dim stquery2 = "INSERT into backup VALUES (" & name & ", '" & Info & "')"
Dim smd2 = New MySqlCommand(stquery2, myconn)
Dim Myreader2 As MySqlDataReader
'smd.ExecuteNonQuery()'
'THE CODE STOPS HERE'
Myreader2 = smd2.ExecuteReader()
'Myreader2.Read()'
MsgBox("The BACKUP INFORMATION HAS BEEN SAVED")
End If
myconn.Close()
Catch ex As Exception
Dim ErrorMessage As String = "alert('" & ex.Message.ToString() & "');"
Page.ClientScript.RegisterStartupScript(Me.GetType(), "ErrorAlert", ErrorMessage, True)
myconn.Close()
End Try
Because your second query is an update, not a select, you need to execute it using the ExecuteNonQuery method. Your commented-out code shows an attempt to call ExecuteNonQuery but on the wrong command object (smd when it should be smd2). Try something like this instead:
myreader.Read()
Dim name As String = myreader.Item("user_name").ToString()
Dim stquery2 = "INSERT into backup VALUES (" & name & ", '" & Info & "')"
Dim smd2 = New MySqlCommand(stquery2, myconn)
smd2.ExecuteNonQuery()
The ExecuteNonQuery method returns the number of rows updated as an int value, so you can capture it if it's valuable to you. In your case it's probably not, but here's how you'd check anyway:
int rowsAdded = smd2.ExecuteNonQuery();
if (rowsAdded == 1) {
// expected this
} else {
// didn't expect this
}
Finally, concatenating strings to build SQL commands can leave you vulnerable to SQL Injection attacks. Please take a look at using parameterized queries. There's a decent example here.
If you want to execute nested Reader, you have to create another connection. You need somethig like
smd2 = New MySqlCommand(stquery2, myconn2)' myconn2 is another connection
OR
Set "MultipleActiveResultSets=True in your connection string.
Also, use ExecuteNonQuery() for Inserting
Dim name As String = myreader("user_name").ToString()
Dim stquery2 = "INSERT into backup VALUES ('" & name & "', '" & Info & "')"
Dim smd2 = New MySqlCommand(stquery2, myconn)
smd.ExecuteNonQuery()
Please use Parameterized query to avoid SQL Injection
The logic is that you need to close your first reader (myreader) before executing another reader (MyReader2) on the same connection.

Web form is not updating tables, why?

I have a web application and on page is an update page to update some profile information. Below is the code I am using to update the table. But I think it is wrong. Does anything stick out? The connection string works cause it is used to read the database to get the profile information, I just removed it due to it containing password/login info for the db.
player is the class of properties that contains player information and ds is the dataset, but I would like to update the database itself online...
Dim connectionString As String = ""
Dim GigsterDBConnection As New System.Data.SqlClient.SqlConnection(connectionString)
GigsterDBConnection.Open()
Dim updatetoursql As String = "UPDATE PLAYERS SET FIRSTNAME = '" & player.FIRSTNAME & "', LASTNAME = '" & player.LASTNAME & "', ADDRESS = '" & player.ADDRESS & "', CITY = '" & player.CITY & "', ZIP = '" & player.ZIP & "', PHONE = '" & player.PHONE & "', EMAIL = '" & player.EMAIL & "', REFFEREDBY = '" & player.REFEREDBY & "' "
updatetoursql = updatetoursql & "PLAYERID = '" & player.PLAYERID & "';"
Dim cmd As New System.Data.SqlClient.SqlCommand(updatetoursql, GigsterDBConnection)
Dim sqlAdapter As New System.Data.SqlClient.SqlDataAdapter(cmd)
sqlAdapter.Update(ds, "PLAYERS")
I think the issue is something the 3 last lines of the code. am I doing it right or is their a better way?
Thanks
Well, apart from the glaring SQL injection issues waiting to bite you ..... (hint: use parametrized queries instead of concatenating together your SQL statement!!)
Dim cmd As New SqlCommand(updatetoursql, GigsterDBConnection)
Dim sqlAdapter As New SqlDataAdapter(cmd)
The problem here is: if you call the SqlDataAdapter constructor this way, what you're passing in is the select command (of the data adapter) - not the update command!
You need to do it this way:
Dim cmd As New SqlCommand(updatetoursql, GigsterDBConnection)
Dim sqlAdapter As New SqlDataAdapter()
sqlAdapter.UpdateCommand = cmd;
Now you've associated your UPDATE statement with the SqlDataAdapter.UpdateCommand and now it should work.
About the SQL injection: I'd strongly recommend using parametrized queries all the time - at least in production code. So instead of concatenating together your query, use this:
Dim updatetoursql As String =
"UPDATE PLAYERS SET FIRSTNAME = #FirstName, LASTNAME = #LastName, " &
"ADDRESS = #Address, CITY = #City, ZIP = #Zip, PHONE = #Phone " &
"EMAIL = #EMail, REFFEREDBY = #ReferredBy, PLAYERID = #PlayerID"
and then before you execute the command or the SqlDataAdapter.Update statement, set those parameters to the values you have. This is much safer and gives you less headaches and possibly even speed improvements (if that single Update query is only cached once in SQL Server memory).
Also, why go the long and complicated way of a SqlDataAdapter at all??
After you've created the SqlCommand and set all the parameters, just call cmd.ExecuteNonQuery(); and you're done!
Dim cmd As New SqlCommand(updatetoursql, GigsterDBConnection)
// set up the parameters here.....
cmd.Parameters.AddWithvalue("#FirstName", FirstName);
... etc.
// just call ExecuteNonQuery - and you're done!
cmd.ExecuteNonQuery();
The big thing that jumps up at me is how open to SQL Injection attacks this code is.
You should not build a SQL string in this manner, but use parameterized queries.
Other then that, you are constructing your adapter incorrectly, as the constructor will take the select command, not the update command. Create the command with the parameterless constructor then assign the command you have created to the UpdateCommand property.

An example of advanced database search

im looking for an example script. I saw one yesterday but for the life of me I can't find it again today.
The task I have is to allow the user to search 1 database table via input controls on an aspx page where they can select and , or , equals to combine fields, generating the sql on the fly with concat/stringbuilder or similar. (it runs behind the corp firewall)
Please can someone point me in the right direction of an example or tutorial
I've been working on the page, but have run into problems. Here is the Page_load;
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim sql As String = ("Select * From Table Where ")
'variables to hold the and or values between fields
Dim andor1v As String = AndOr1.SelectedValue.ToString()
Dim andor2v As String = AndOr2.SelectedValue.ToString()
Dim andor3v As String = AndOr3.SelectedValue.ToString()
Dim andor4v As String = AndOr4.SelectedValue.ToString()
Dim andor5v As String = AndOr5.SelectedValue.ToString()
Dim andor6v As String = AndOr6.SelectedValue.ToString()
'variables to stop web control inputs going direct to sql
Dim name As String = NameSearch.Text.ToString()
Dim email As String = EmailSearch.Text.ToString()
Dim city As String = CitySearchBox.Text.ToString()
Dim province As String = ProvinceSelect.SelectedValue.ToString()
Dim qualifications As String = QualificationsObtained.Text.ToString()
Dim competencies As String = CompetenciesDD.SelectedValue.ToString()
Dim expertise As String = Expertiselist.SelectedValue.ToString()
If NameSearch.Text IsNot String.Empty Then
sql += "Surname LIKE '%" & name & "%' "
End If
If EmailSearch.Text IsNot String.Empty Then
sql += andor1v & " Email LIKE '%" & email & "%' "
End If
If CitySearchBox.Text IsNot String.Empty Then
sql += andor2v & " City LIKE '%" & city & "%' "
End If
If QualificationsObtained.Text IsNot String.Empty Then
sql += andor3v & " (institutionquals1 LIKE '%" & qualifications & "%') OR " & _
"(institutionquals2 LIKE '%" & qualifications & "%') OR " & _
"(institutionquals3 LIKE '%" & qualifications & "%') OR " & _
"(institutionquals4 LIKE '%" & qualifications & "%') "
End If
Dim selectedrow As String = CompetenciesDD.SelectedValue.ToString
Dim selectedquals As String = NQFlevel.SelectedValue.ToString
If CompetenciesDD.SelectedValue.ToString IsNot "0" And selectedquals = 0 Then
sql += (selectedrow & " = 1 ")
ElseIf selectedrow = "assessortrue" And selectedquals IsNot "0" Then
sql += andor4v & (" assessortrue=1 and assessorlvl=" & selectedquals)
ElseIf selectedrow = "coordinatortrue" And selectedquals IsNot "0" Then
sql += andor4v & ("coordinatortrue=1 and coordinatorlvl=" & selectedquals)
ElseIf selectedrow = "facilitatortrue" And selectedquals IsNot "0" Then
sql += andor4v & ("facilitatortrue=1 and facilitatorlvl=" & selectedquals)
ElseIf selectedrow = "moderatortrue" And selectedquals IsNot "0" Then
sql += andor4v & ("moderatortrue=1 and moderatorlvl=" & selectedquals)
ElseIf selectedrow = "productdevelopertrue" And selectedquals IsNot "0" Then
sql += andor4v & ("productdevelopertrue=1 and productdeveloperlvl=" & selectedquals)
ElseIf selectedrow = "projectmanagertrue" And selectedquals IsNot "0" Then
sql += andor4v & ("projectmanagertrue=1 and projectmanagerlvl=" & selectedquals)
End If
Response.Write(sql)
End Sub
After an hours tinkering the code is now looking as it does above ^
Now the problem im faced with is if a user does not enter a value for surname (the first field) but does enter a value for email (or any subsequent fields), the sql produced has an extra and like this;
Select * From Table Where And Email LIKE '%test%'
I'm also looking for a way to take the OR option into account. Do you think this should be done as Martin says where the whole query is either an and or an or and not a mix of the 2? Then I should be able to take out all the and/or drop downs?
Thanks.
NB: I'm not really looking for comments on how I should parameterise or about sql injection.
Regarding your issue with users not selecting an option you could just remove the "please select" and have it default to "and"
Also what is the desired behaviour if they select a mix of ANDs and ORs?
By default the ANDs will be evaluated first in the absence of any brackets
http://msdn.microsoft.com/en-us/library/ms186992.aspx
So if they enter
name="Fred" or email="blah" and
city="london" and province="xyz" or
qualifications="Degree"
I'm not really sure what the desired semantics would be?
Is it
(name="Fred" or email="blah") and
city="london" and (province="xyz" or
qualifications="Degree")
or
(name="Fred" or (email="blah" and
city="london") and province="xyz") or
qualifications="Degree"
Or something different? Maybe you should restrict them to AND or OR for the whole query or allow them to disambiguate either by typing in advanced search syntax with brackets or by providing a query builder UI.
To avoid sql injection and allow a dynamic search I would probably write a stored procedure something like this. If nothing is selected send DBNull.Value in the ado.net parameters collection as the parameter value. With this approach you can check any columns you want and if they are not selected by the user they will be ignored.
EDIT: I just saw that you are not allowed to use stored procedures. I changed my answer below to show a parameterized sql statement
SELECT * FROM TABLE
WHERE ([name] = #name OR #name IS NULL)
AND (email = #email OR #email IS NULL)
AND (city = #city OR #city IS NULL)
AND (province = #province OR #province IS NULL)
AND (qualifications = #qualifications OR #qualifications IS NULL)
AND (competencies = #competencies OR #competencies IS NULL)
AND (expertise = #expertise OR #expertise IS NULL)
Concat strings to build a query is never a good idea. You should use a stored procedure or parametrized queries
I have done this "dynamic" type query interface on classic asp.
The advice that I give to you is that you are trying to do the whole query in one page load so...
Look to "building" the query via a "wizard" type interface - either ajax for the newness or simple multiple pages for each part of the query building.
This is essence gives you "persitance" via what ever means you have (session, dbstore, cookie etc) for each part of the query and you have can sanity check each part of the query as you build.
Dim sql As String = ("Select * From Table Where **1=1**")
'variables to hold the and or values between fields
Dim andor1v As String = AndOr1.SelectedValue.ToString()
Dim andor2v As String = AndOr2.SelectedValue.ToString()
Dim andor3v As String = AndOr3.SelectedValue.ToString()
Dim andor4v As String = AndOr4.SelectedValue.ToString()
Dim andor5v As String = AndOr5.SelectedValue.ToString()
Dim andor6v As String = AndOr6.SelectedValue.ToString()
'variables to stop web control inputs going direct to sql
Dim name As String = NameSearch.Text.ToString()
Dim email As String = EmailSearch.Text.ToString()
Dim city As String = CitySearchBox.Text.ToString()
Dim province As String = ProvinceSelect.SelectedValue.ToString()
Dim qualifications As String = QualificationsObtained.Text.ToString()
Dim competencies As String = CompetenciesDD.SelectedValue.ToString()
Dim expertise As String = Expertiselist.SelectedValue.ToString()
If NameSearch.Text IsNot String.Empty And andor1v IsNot "0" Then
sql += "**and** Surname LIKE '%" & name & "%' "
ElseIf NameSearch.Text IsNot String.Empty And andor1v Is "0" Then
sql += "**or** Surname LIKE '%" & name & "%' "
End If
....additional logic here.....
Response.Write(sql)
End Sub
note the ** parts. 1=1 evaluates to true on most DBMS. This allows you to just start concatenating your or / ands on to it without worrying about ()'s

Writing an update query in asp.net (access database) (visual basic)

I have this code:
Dim pathString As String = HttpContext.Current.Request.MapPath("Banking.mdb")
Dim odbconBanking As New OleDbConnection _
("Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" + pathString)
Dim sql As String
sql = "UPDATE tblAccounts balance = " & CDbl(balance + value) & " WHERE(accountID = " & accountID & ")"
odbconBanking.Open()
Dim cmd As New OleDbCommand(sql, odbconBanking)
cmd.ExecuteNonQuery()
However, an exception is thrown, when I run it:
Syntax error in UPDATE statement.
I tried to run a similar statement in Access and it works fine.
I think the missing is SET.
Try: UPDATE table SET field = newvalue WHERE criteria;
Just modify:
sql = "UPDATE tblAccounts SET balance = " & CDbl(balance + value) & " WHERE(accountID = " & accountID & ")"
http://office.microsoft.com/en-us/access/HA100765271033.aspx
The SQL Statement definitely is missing the SET keyword. Also, I suggest you to brush up on parameterized query:
Dim sql As String = "UPDATE tblAccounts " & _
"SET balance = ? " & _
"WHERE(accountID = ?)"
Dim cmd As New OleDbCommand(sql, odbconBanking)
cmd.Parameters.Add("Balance", CDbl(balance + value))
cmd.Parameters.Add("AccountId", accountID
cmd.ExecuteNonQuery()
This way, not only is the SQL Statment is clearer, it help prevents possible SQL injection attacks.
You are missing SET as part of UPDATE.
It should be UPDATE tablename SET fieldname = ... WHERE [criteria].
On a side note, you are using classic asp style code inside asp.net. I will suggest reading some docs on ASP.net and how to design applications in a layered manner.
A good start is here: Enterprise Library's Data Access Application Block
Link: https://web.archive.org/web/20210612110113/https://aspnet.4guysfromrolla.com/articles/030905-1.aspx

Resources