在vb.net中嵌套sql查询

时间:2015-10-26 09:46:33

标签: sql sql-server vb.net

当我尝试嵌套sql查询时,以下代码会出现以下错误。

  

已经有一个与此命令关联的打开DataReader,必须先关闭

     

reader4 = cmd4.ExecuteReader()

堆栈追踪:

[InvalidOperationException: There is already an open DataReader associated with this Command which must be closed first.]
   System.Data.SqlClient.SqlInternalConnectionTds.ValidateConnectionForExecute(SqlCommand command) +5333807
   System.Data.SqlClient.SqlConnection.ValidateConnectionForExecute(String method, SqlCommand command) +51
   System.Data.SqlClient.SqlCommand.ValidateCommand(String method, Boolean async) +155
   System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite) +82
   System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) +53
   System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) +137
   System.Data.SqlClient.SqlCommand.ExecuteReader() +99
   CW_Recruiter_postjob.btnPostJob_Click(Object sender, EventArgs e) in C:\Users\Khav\Documents\Visual Studio 2013\WebSites\BSE14BFT_140928\CW\Recruiter\postjob.aspx.vb:42
   System.EventHandler.Invoke(Object sender, EventArgs e) +0
   System.Web.UI.WebControls.Button.OnClick(EventArgs e) +9628722
   System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) +103
   System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +10
   System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +13
   System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +35
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1724

代码:

 Protected Sub btnPostJob_Click(sender As Object, e As EventArgs) Handles btnPostJob.Click
        Dim con As New SqlConnection(ConfigurationManager.ConnectionStrings("JPortalCS").ConnectionString)
        con.Open()
        Dim cmd As New SqlCommand("INSERT INTO [JobDetails].[Job](Job_Title,Job_Desc,Start_Date,End_Date,Status,Category_ID,Recruiter_ID) VALUES (@Title,@Desc,@Start,@End,@Status,@Category_ID,@Recruiter_ID)", con)
        cmd.Parameters.AddWithValue("@Title", job_title.Text)
        cmd.Parameters.AddWithValue("@Desc", job_desc.Text)
        cmd.Parameters.AddWithValue("@Start", DateTime.Now.ToString("d"))
        cmd.Parameters.AddWithValue("@End", DateTime.Now.ToString("d"))
        cmd.Parameters.AddWithValue("@Status", "Available")
        'getting category_id 
        Dim reader As SqlDataReader
        Dim cmd2 As New SqlCommand("SELECT * FROM [JobDetails].[Category] where Category_Desc=@cat", con)
        cmd2.Parameters.AddWithValue("@cat", ddlCategory.SelectedValue)
        reader = cmd2.ExecuteReader()
        Dim catid As Integer
        If reader.HasRows Then
            reader.Read()
            catid = reader.Item("Category_ID")
        End If
        'end
        'getting user_id
        Dim reader4 As SqlDataReader
        Dim cmd4 As New SqlCommand("SELECT * FROM [UserDetails].[User] where User_Name=@username", con)
        cmd4.Parameters.AddWithValue("@username", Session("login_user"))
        reader4 = cmd4.ExecuteReader()
        Dim userid As Integer
        If reader4.HasRows Then
            reader4.Read()
            userid = reader4.Item("User_ID")
        End If
        'getting recruiter_id 
        Dim reader3 As SqlDataReader
        Dim cmd3 As New SqlCommand("SELECT * FROM [UserDetails].[Recruiter] where User_ID=@user", con)
        cmd3.Parameters.AddWithValue("@user", userid)
        reader3 = cmd3.ExecuteReader()
        Dim recruterid As String = ""
        If reader3.HasRows Then
            reader3.Read()
            recruterid = reader3.Item("Recruiter_ID")
        End If
        'end
        cmd.Parameters.AddWithValue("@Category_ID", catid)
        cmd.Parameters.AddWithValue("@Recruiter_ID", recruterid)
        cmd.CommandType = CommandType.Text
        cmd.ExecuteNonQuery()
        con.Close()
    End Sub

1 个答案:

答案 0 :(得分:2)

错误消息是自解释的:在一个连接上只能有一个数据读取器处于活动状态(请参阅documentation中的备注)。
你可以找到罪魁祸首,试图了解哪些未被处置的对象是以更干净(可读,优雅)的方式责备或重写你的代码。

下面是一个代码应该是什么样子的示例:

Dim catid As Integer
Dim userid As Integer
'getting category_id 
Using cmd As New SqlCommand("SELECT * FROM [JobDetails].[Category] where Category_Desc=@cat", con)
    cmd.Parameters.AddWithValue("@cat", ddlCategory.SelectedValue)
    Using reader As SqlDataReader = cmd.ExecuteReader()
        If reader.HasRows Then
            reader.Read()
            catid = reader.Item("Category_ID")
        End If
    End Using
End Using
'end
'getting user_id
Using cmd As New SqlCommand("SELECT * FROM [UserDetails].[User] where User_Name=@username", con)
    cmd.Parameters.AddWithValue("@username", Session("login_user"))
    Using reader As SqlDataReader = cmd.ExecuteReader()
        If reader.HasRows Then
            reader.Read()
            userid = reader4.Item("User_ID")
        End If
    End Using
End Using

这样就可以避免这个问题,因为SqlDataReader对象在使用后会立即处理,并且不会使下一次调用崩溃。

另一个可以提高整体可读性和稳定性的变化是在sql查询中使用字段的显式命名:

SqlCommand("SELECT * FROM [JobDetails].[Category] where Category_Desc=@cat", con)

可以写成:

SqlCommand("SELECT Category_ID FROM [JobDetails].[Category] where Category_Desc=@cat", con)

如果您只使用一个值,则无需检索整行 使用上述解决方案,您甚至可以重写调用以将Category_ID字段检索为:

'getting category_id 
Using cmd As New SqlCommand("SELECT Category_ID FROM [JobDetails].[Category] where Category_Desc=@cat", con)
    cmd.Parameters.AddWithValue("@cat", ddlCategory.SelectedValue)
    catid = cmd.ExecuteScalar()
End Using
'end

查看ExecuteScalar

的行为和限制的文档