Friday, February 24, 2012

Error: There is already an open DataReader associated with this Command

Hi

I'm trying to loop through all the records in a recordset and perform a database update within the loop. The problem is that you can't have more than one datareader open at the same time. How should I be doing this?

cmdPhoto =New SqlCommand("select AuthorityID,AuthorityName,PREF From qryStaffSearch where AuthorityType='User' Order by AuthorityName", conWhitt)

conWhitt.Open()

dtrPhoto = cmdPhoto.ExecuteReader

While dtrPhoto.Read()

IfNot File.Exists("D:WhittNetLive\Web\images\staffphotos\pat_images_resize\" & dtrPhoto("PRef") &".jpg")Then

cmdUpdate =New SqlCommand("Update tblAuthority Set NoPhoto = 1 Where AuthorityID =" & dtrPhoto("AuthorityID"), conWhitt)

cmdUpdate.ExecuteNonQuery()

EndIf

EndWhile

Thanks

What you could do is create a update sub that you just passed the ID of the photo to, which then set the NoPhoto to 1


i.e.


While dtrPhoto.Read()

IfNot File.Exists("D:WhittNetLive\Web\images\staffphotos\pat_images_resize\" & dtrPhoto("PRef") &".jpg")Then

SetPhoto(dtrPhoto("AuthorityID"))

cmdUpdate.ExecuteNonQuery()

Then create a sub

Sub SetPhoto(Byval id as Integer)

' Your database stuff

cmdUpdate =New SqlCommand("Update tblAuthority Set NoPhoto = 1 Where AuthorityID =" & id, conWhitt)

End Sub


Hope that helpsSmile

|||

Thanks, I thought that would work but I get the same errorSad

PrivateSub Page_Load(ByVal senderAs System.Object, _

ByVal eAs System.EventArgs)HandlesMyBase.Load

Dim cmdPhotoAs SqlCommand

Dim dtrPhotoAs SqlDataReader

cmdPhoto =New SqlCommand("select AuthorityID,AuthorityName,PREF From qryStaffSearch where AuthorityType='User' Order by AuthorityName", conWhitt)

conWhitt.Open()

dtrPhoto = cmdPhoto.ExecuteReader

While dtrPhoto.Read()

IfNot File.Exists("D:WhittNetLive\Web\images\staffphotos\pat_images_resize\" & dtrPhoto("Pref") &".jpg")And dtrPhoto("Pref") <>""Then

NoPhotoUpdate(dtrPhoto("Pref"))

EndIf

EndWhile

conWhitt.Close()

dtrPhoto.Close()

EndSub

Sub NoPhotoUpdate(ByVal PrefAsInteger)

Dim cmdUpdateAs SqlCommand

cmdUpdate =New SqlCommand("Update tblAuthority Set NoPhoto = 1 Where Pref =" & Pref, conWhitt)

cmdUpdate.ExecuteNonQuery()

EndSub

|||

Hi there

Sorry i didnt reply sooner, i was moving house!


The problem your having is that the NoPhotoUpdate sub cannot access the datareader of the page_load sub.

(its a bit of a git to get your head around at first, then when you do you will wonder how you ever managed without it!)

You might want to get a book on OOP for asp.net - The dummies book one is quite good (and written by a comedian!), but covers only vb1.1 (AFAIK).

Anyways that said..

Private Sub Page_Load(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles MyBase.Load
SelectPhoto()

End Sub


Sub SelectPhoto()
Dim cmdPhoto As SqlCommand
Dim dtrPhoto As SqlDataReader

cmdPhoto = New SqlCommand("select AuthorityID,AuthorityName,PREF From qryStaffSearch where AuthorityType='User' Order by AuthorityName", conWhitt)

conWhitt.Open()
dtrPhoto = cmdPhoto.ExecuteReader

While dtrPhoto.Read()

If Not File.Exists("D:WhittNetLive\Web\images\staffphotos\pat_images_resize\" & dtrPhoto("Pref") & ".jpg") And dtrPhoto("Pref") <> "" Then

NoPhotoUpdate(dtrPhoto("Pref"))

End If

End While

conWhitt.Close()

dtrPhoto.Close()

End Sub

Sub NoPhotoUpdate(ByVal Pref As Integer)

Dim strConnectionString As String
strConnectionString = ' Your connection String

Dim DBConn As New SqlConnection(strConnectionString)
Dim DBCmd As New SqlCommand
Dim DBAdap As New SqlDataAdapter
DBConn.Open()

DBCmd = New SqlCommand("Update tblAuthority Set NoPhoto = 1 Where Pref = @.Pref", DBConn)
DBCmd.Parameters.Add("@.Pref", SqlDbType.NVarChar).Value = Pref
DBCmd.ExecuteNonQuery()
DBCmd.Dispose()
DBAdap.Dispose()
DBConn.Close()
DBConn = Nothing

End Sub

The whole @. thing is a safer way to pass paramaters to your SQL

http://weblogs.asp.net/scottgu/archive/2006/09/30/Tip_2F00_Trick_3A00_-Guard-Against-SQL-Injection-Attacks.aspx for a explanation

Notice how each sub is a seperate little program, with one activating the other whilst passing data.

I hope ive been of some help

|||

Thanks that works. Thanks also for the heads up about sql injection attacks. I do normally pass my parameters the safe way but was not aware of the dangers of not doing so.

Enjoy your new houseSmile

|||

I'm having the same problem and i have to believe there is a better solution then creating a sep sub and then creating another connection. Based on your solution you should problably just create a second connection in the first sub and just use that, no need for the whole extra nophotoupdate sub.

Having said that there needs to be a solution for activly using the same connection at the same time. In good old ADO days we were able to open many recordsets and execute sql commands all at the same time with one DB connection. There is a way to do this here.

RageMonkey:


Sub NoPhotoUpdate(ByVal Pref As Integer)

Dim strConnectionString As String
strConnectionString = ' Your connection String

Dim DBConn As New SqlConnection(strConnectionString)
Dim DBCmd As New SqlCommand
Dim DBAdap As New SqlDataAdapter
DBConn.Open()

DBCmd = New SqlCommand("Update tblAuthority Set NoPhoto = 1 Where Pref = @.Pref", DBConn)
DBCmd.Parameters.Add("@.Pref", SqlDbType.NVarChar).Value = Pref
DBCmd.ExecuteNonQuery()
DBCmd.Dispose()
DBAdap.Dispose()
DBConn.Close()
DBConn = Nothing

End Sub

|||

I'm having the same problem and i have to believe there is a better solution then creating a sep sub and then creating another connection. Based on your solution you should problably just create a second connection in the first sub and just use that, no need for the whole extra nophotoupdate sub.

Having said that there needs to be a solution for activly using the same connection at the same time. In good old ADO days we were able to open many recordsets and execute sql commands all at the same time with one DB connection. There is a way to do this here.

RageMonkey:


Sub NoPhotoUpdate(ByVal Pref As Integer)

Dim strConnectionString As String
strConnectionString = ' Your connection String

Dim DBConn As New SqlConnection(strConnectionString)
Dim DBCmd As New SqlCommand
Dim DBAdap As New SqlDataAdapter
DBConn.Open()

DBCmd = New SqlCommand("Update tblAuthority Set NoPhoto = 1 Where Pref = @.Pref", DBConn)
DBCmd.Parameters.Add("@.Pref", SqlDbType.NVarChar).Value = Pref
DBCmd.ExecuteNonQuery()
DBCmd.Dispose()
DBAdap.Dispose()
DBConn.Close()
DBConn = Nothing

End Sub

|||

I found the solution on the msdn forums. Seems to only work for SQL 2005

"This is due to a change in the default setting for MARs. It used to be on by default and we changed it to off by default post RC1. So just change your connection string to add it back (add MultipleActiveResultSets=True to connection string)."

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=123691&SiteID=1

No comments:

Post a Comment