SQLDataReader find value of each row - asp.net

I used to use datasets instead of sqldatareaders and I used to be able to do something like this
If dataset.tables(0).Rows(0)(1).ToString()) = "N" Then
lbl.Text = dataset.tables(0).Rows(0)(2).ToString())
Else
'Do Nothing
End If
This obviously doesn't work with sqldatareaders.
I have code to see if the SQLDatareader has any rows but was wondering if there was a way to get the value of each row
I'm guessing this is possible and i've had a look around but can't seem to find anything
Dim conn As SqlConnection = New SqlConnection("server='h'; user id='w'; password='w'; database='w'; pooling='false'")
conn.Open()
Dim query As New SqlCommand("DECLARE #investor varchar(10), #sql varchar(1000) Select #investor = 69836 select #sql = 'SELECT * FROM OPENQUERY(db,''SELECT * FROM table WHERE investor = ''''' + #investor + ''''''')' EXEC(#sql)", conn)
Dim oDR As SqlDataReader = query.ExecuteReader()
If oDR.HasRows or dataset.tables(0).Rows(0)(1).ToString()) = "N" Then
lbl.Text = dataset.tables(0).Rows(0)(2).ToString())
Else
'Do Nothing
End If
That is the code I have at the moment which obviously doesn't work
Any ideas?
Thanks

When you use the data reader you have to step through each row yourself. Using HasRows is a good start, for it will tell you if the returned result set is empty.
To iterate through the result set you should use the Read() method. It will return true if you are at a row and false when you have moved past the last row.
My Vb is poor so I will give you an example in C# instead:
if (oDR.HasRows && oDR.Read())
{
if (oDR.GetString(0) == "N")
{
lbl.Text = oDr.GetString(1);
}
}
Here I first check that we have a result set with data and then try to move to the first row. If this succeeds I then read the string value of the first column and compare it to "N". If the value is equal to "N" I set the Text property of the lbl variable to the string value of the second column.
This should be equivalent to your algorithm with the dataset. I recommend that you read the MSDN documentation for the SqlDataReader. It is quite good and the example code is useful.

Related

Read multiple items from list box to query information from a database

Ok so what I'm trying to do is allow the users of my web form in asp.net to select multiple assets from a list box. When they select these assets and press the select button it fires the following code which should run through the selected indices, query the DB for the description and asset tag's, and populate the Description and Asset tag boxes with those values. Working through this I've been able to get it to read the values from the database and populate the fields but it would only populate the value from the first selected item and it would just insert the same value equal to the number of times equal to the number of items selected in the inbox. I tried my current code to run through the indices a little better but it seems to be failing the If statement and I just can't figure out why. Any help is appreciated, thanks everyone!
Dim i As Integer
For i = 0 To lstAssets.GetSelectedIndices.Count
If lstAssets.Items(i).Selected = True Then
Dim str2 As String = lstAssets.Items(i).Value.ToString
Dim cs As New OracleConnection(System.Configuration.ConfigurationManager.ConnectionStrings("CSIWebUpd").ConnectionString)
Dim ds As String = cs.DataSource
Dim cn As OracleConnection = New OracleConnection("user id=webupd;password=webupd;data source=" + ds)
Dim sql As String = "SELECT description, tag FROM assets WHERE id = :id"
Dim cmd As New OracleCommand(sql, cn)
cmd.Parameters.Add(":id", OracleDbType.Varchar2).Value = str2
cmd.CommandType = CommandType.Text
cmd.BindByName = True
cn.Open()
Dim dr As OracleDataReader = cmd.ExecuteReader()
cmd.ExecuteNonQuery()
dr.Read()
desc = dr.GetString(0).ToString
ass = dr.GetString(1).ToString
If txtDescription.Text = Nothing Then
txtDescription.Text = dr.GetString(0).ToString
Else
txtDescription.Text = txtDescription.Text + Chr(13) + Chr(10) + dr.GetString(0).ToString
End If
If txtAsset.Text = Nothing Then
txtAsset.Text = dr.GetString(1).ToString
Else
txtAsset.Text = txtAsset.Text + Chr(13) + Chr(10) + dr.GetString(1).ToString
End If
cmd.Dispose()
cn.Close()
End If
Next i
UpdatePanel1.UpdateMode = UpdatePanelUpdateMode.Conditional
UpdatePanel1.Update()
I would work with the SelectedIndices values in this way
For Each i in lstAssets.GetSelectedIndices
Now i contains the index of the items selected not the offset of the GetSelectedIndices array
The GetSelectedIndices returns an array where every element of the array is the index in the Items collection where you have an item selected.
An example could explain better:
Supposing the the items selected are 1, 5 6 (Count=3), your code set the value of i to 0,1,2 and then uses that value to lookup the ID in the items collection, but the following check on lstAssets.Items(i).Selected found just the item at index 1 as selected. Instead using the for each approach you get the values 1,5,6.

index was outside the bounds of the array in asp.net using vb

I'm getting the following error thrown:
index was outside the bounds of the array
When using this code:
con.Open()
qur = "select Username,password from registration where Username='" + TextBox1.Text + "'"
cmd = New SqlCommand(qur, con)
dr = cmd.ExecuteReader()
If dr.HasRows() Then
dr.Read()
Session("us1") = dr.GetValue(11).ToString()
Session("ps1") = dr.GetValue(12).ToString()
If Session("us1") = TextBox1.Text And Session("ps1") = TextBox2.Text Then
Response.Redirect("APP.aspx")
End If
End If
End Sub
Could someone please point out where/why it's going wrong?
Check your ordinals. You might be giving an index which does not exist.
Index starts from 0. Instead of 11,12 you might want to try with 10, 11 for GetValue
I would suspect the problem lies with:
Session("us1") = dr.GetValue(11).ToString()
Session("ps1") = dr.GetValue(12).ToString()
However, don't use ordinals use column names:
Session("us1") = dr("column1").ToString()
Session("ps1") = dr("column2").ToString()
Ordering can easily change blowing up your ordinals. By using column names you're not dependent on the order so you won't get an index error.
If the column doesn't exist you WILL get another kind of error however.
You're trying to get values for fields that don't exist:
dr.GetValue(11)
and
dr.GetValue(12)
Note that your query is only selecting two columns (username and password)
select Username,password
Either use GetValue(0) and GetValue(1) or use column names dr("Username") and dr("password")

DataReader.Read() skips first row of recordset

I am trying to check the value of a field before decided what to input into a drop down list in ASP.net.
I am using datareader.Read() in order to read the recordset so I can do this. However this then skips the first row of data . . The drop down box is basically a list of sizes and colours . . . So currently I am missing the first size.
Here is the code:
Using cmd As New SqlCommand("doGetAllSizesForProduct", oConn)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("#id", CType(Request.QueryString("id"), Integer))
oConn.Open()
Using dr As SqlDataReader = cmd.ExecuteReader()
If dr.HasRows() = True Then
dr.Read()
ddlSize.Visible = True
pnlSize.Visible = True
pnlNoStock.Visible = False
If dr("colour") = "None" Then
ddlSize.DataTextField = "size"
Else
ddlSize.DataTextField = "sizeColour"
End If
ddlSize.DataValueField = "mapperid"
ddlSize.DataSource = dr
ddlSize.DataBind()
Else
End If
dr.Close()
End Using
End Using
I guess either there must be another method other than Read or a way to stop it skipping the first record?
I've never seen a datareader being used as the datasource. What I think is happening is that your first call to dr.Read() is skipping to the first record as expected. However, when you assign the reader as the datasource, it's doing its own dr.Read() logic inside which starts at the next record. This could explain why you're not seeing the first item. Try modifying your code like this to use a DataTable instead (warning, didn't test this):
using dr as SqlDataReader = cmd.ExecuteReader()
if dr.HasRows() then
ddlSize.Visible = True
pnlSize.Visible = True
pnlNoStock.Visible = False
While dr.Read()
dim Value as string = dr("mapperid")
dim Text as string = if(dr("colour") = "None",dr("size"),dr("sizeColour"))
ddlSize.Items.Add(New ListItem(Text, Value))
End While
end if
dr.Close()
end using
How about changing the doGetAllSizesForProduct stored procedure to return two recordsets?
The first recordset can return a single row giving an indication of what type of data is contained in the second recordset, which contains the same content as previously.
you are not supposed to use the DataReader like this, executing a single Read to get the value in the first record then binding the UI control to it like this:
ddlSize.DataValueField = "mapperid"
ddlSize.DataSource = dr
ddlSize.DataBind()
I would personally use a DataTable for binding to a UI control, or try to remove the call to dr.Read() and see how it works.

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

compare data in a vb.net dataset with values in an array list

I'm looking for an efficient way of searching through a dataset to see if an item exists. I have an arraylist of ~6000 items and I need to determine which of those doesn't exist in the dataset by comparing each item within the arraylist with data in a particular column of the dataset.
I attempted to loop through each item in the dataset for each in the arraylist but that took forever. I then attempted to use the RowFilter method below. None of which looks to be efficient. Any help is greatly appreciated, as you can tell I'm not much of a programmer...
example:
Dim alLDAPUsers As ArrayList
alLDAPUsers = clsLDAP.selectAllStudents
Dim curStu, maxStu As Integer
maxStu = alLDAPUsers.Count
For curStu = 0 To maxStu - 1
Dim DomainUsername As String = ""
DomainUsername = alLDAPUsers.Item(curStu).ToString
Dim filteredView As DataView
filteredView = dsAllStudents.Tables(0).DefaultView
filteredView.RowFilter = ""
filteredView.RowFilter = "szvausr_un = '" & DomainUsername & "'"
Dim returnedrows As Integer = filteredView.Count
If returnedrows = 0 Then
'' Delete the user...
End If
Next
You can get better performance by Sorting the list and ordering the dataset. Then you can walk them together, matching as you go. This is especially true since you are probably already ordering the dataset at least (or, you should be) in the sql query that creates it, making that step essentially free.
You should consider using a generic list rather than an ArrayList, and some other stylistic points on your existing code:
Dim LDAPUsers As List(Of String) = clsLDAP.selectAllStudents
For Each DomainUsername As String in LDAPUsers
Dim filteredView As DataView = dsAllStudents.Tables(0).DefaultView
filteredView.RowFilter = "szvausr_un = '" & DomainUsername & "'"
If filteredView.Count = 0 Then
'' Delete the user...
End If
Next
This does the same thing as your original snippet, but in half the space so it's much cleaner and more readable.
Try switching your array list to Generics. From what I understand they are much faster than an array list.
Here is a previous SO on Generics vs Array List
If you use generics as suggested, you can have two Lists of string and do the following:
for each s as string in LDAPUsers.Except(AllStudents)
''Delete the user (s)
next
Where LDAPUsers and AllStudents are both List(Of String)
Edit:
You can also change the except to:
LDAPUsers.Except(AllStudents, StringComparer.InvariantCultureIgnoreCase)
to ignore case etc.
Edit 2:
To get the generic lists could be as simple as:
Dim LDAPUsers as new List(Of String)(alLDAPUsers.Cast(Of String))
Dim AllStudents as new List(OfString)()
for each dr as DataRow in dsAllStudents.Tables(0).Rows
AllStudents.Add(dr("szvausr_un"))
next
Or you can go with the Linq-y goodness as Joel mentions, but my exposure to that is limited, unfortunately...
Like others have said, generics or linq would be better options. However, I wanted to point out that you don't need to use a DataView. The datatable has a Select method...
dsAllStudents.Tables(0).Select("szvausr_un = '" & DomainUserName & "'")
It returns an array of DataRows. I'm sure it will perform just as poorly as the view but I think it's a little cleaner.
Get the Dim statements out of the loop.... Your performance is suffering from repeated variable instantiation and reallocation.
Also remove any statements you dont need (rowfilter = "")
Dim alLDAPUsers As ArrayList
Dim DomainUsername As String
Dim curStu, maxStu As Integer
Dim filteredView As DataView
Dim returnedrows As Integer
alLDAPUsers = clsLDAP.selectAllStudents
maxStu = alLDAPUsers.Count
For curStu = 0 To maxStu - 1
DomainUsername = alLDAPUsers.Item(curStu).ToString
filteredView = dsAllStudents.Tables(0).DefaultView
filteredView.RowFilter = "szvausr_un = '" & DomainUsername & "'"
returnedrows = filteredView.Count
If returnedrows = 0 Then
'' Delete the user...
End If
Next

Resources