简体   繁体   中英

InvalidOperationException on SqlCommand.ExecuteScalar()

I'm running a method that performs a query, then tries to execute another query before I close the connection. The first query executes fine, but the second causes the:

InvalidOperationException on the SqlCommand.ExecuteScalar() method.

I had this running flawlessly earlier, but something has changed that I can't seem to track down. I'm testing to see if the connection is closed or null prior to executing the query, but it is NOT null or closed. So this one has me confused. Anyone have an idea what's going on?

The query being executed is very simple:

SELECT COUNT(*) 
FROM browsers;

I've tested this in SQL Server Management Studio against the database, and it works just fine.

    internal static String[,] executeSelect(SqlConnection conn, Query query, Editor reference)
    {
        if (conn == null)
        {
            throw new System.ArgumentNullException("The SqlConnection parameter to method CSED.SQLServerdb.executeSelect(...) is null");
        }
        if (query == null)
        {
            throw new System.ArgumentNullException("The Query parameter to method CSED.SQLSererdb.executeSelect(...) is null");
        }

        String[,] data = null;
        SqlCommand cmd = null;
        SqlDataReader rdr = null;
        SqlCommand cmd2 = null;
        SqlCommand cmd3 = null;

        try
        {
            Debug.WriteLine("SQLServerdb.executeSelect - query: " + query.ToString());
            cmd = new SqlCommand(query.ToString(), conn);
            rdr = cmd.ExecuteReader();
            Field[] flds = query.Fields;
            int columns = flds.Length;
            //Debug.WriteLine("SQLServerdb.executeSelect -columns: " + columns);
            int recordCount = 0;
            List<TableRow> rows = new List<TableRow>();
            TableRow tr = null;
            while (rdr.Read())
            {
                tr = new TableRow();
                recordCount++;
                for (int i = 0; i < columns; i++)
                {
                    tr.Add(DRExtension.GetStringOrNull(rdr, i));
                }
                rows.Add(tr);
            }


            data = convert2DArray(rows, columns);

            //If reference to the class Editor is null then this Database class isn't being used
            //in conjunction with the Editor class.  Therefore, we don't need to calculate the number
            //of records returned from the query.
            if (reference != null && reference.IsUsingSSP)
            {
                bool flag = false;
                int foundrows = 0;
                //GET THE NUMBER OF RECORDS RETURNED BASED ON THE ORIGINAL QUERY.
                String queryStr = "";
                if (query.HaveWhereConditions)
                {
                    queryStr = "SELECT COUNT(*) FROM " + query.GetParentTable() + query.prepareWhere(query.WhereConditions);
                }
                else
                {
                    queryStr = "SELECT COUNT(*) FROM " + query.GetParentTable();
                    flag = true;
                }
                Debug.WriteLine("queryStr: " + queryStr);
                if(conn.State == ConnectionState.Closed)
                    Debug.WriteLine("conn is closed");
                if(conn == null)
                    Debug.WriteLine("conn is NULL");
                cmd2 = new SqlCommand(queryStr, conn);
                object result = cmd2.ExecuteScalar();  //This is where I get the error
                if (result != null)
                {
                    foundrows = Convert.ToInt32(result);
                    query.IFilteredTotal = foundrows;
                }

                //Debug.WriteLine("SQLServerdb.executeSelect - foundrows: " + foundrows);

                //GET THE TOTAL NUMBER OF RECORDS IN THE TABLE.
                if (flag == false)
                {
                    queryStr = "SELECT COUNT(*) FROM " + query.GetParentTable();
                    //Debug.WriteLine("SQLServerdb.executeSelect - queryStr: " + queryStr);
                    cmd3 = new SqlCommand(queryStr, conn);
                    result = cmd3.ExecuteScalar();
                    if (result != null)
                    {
                        int r = Convert.ToInt32(result);
                        // Debug.WriteLine("SQLServerdb.executeSelect - Number of Records in the Table: " + r);
                        query.ITotal = r;
                    }

                }
                else
                {
                    query.ITotal = foundrows;
                }
            }           

        }
        catch (SqlException sqle)
        {
            String extra = "SQL Problem: " + sqle.Message + Constants.NEWLINE;
            extra += "Vendor Error: " + sqle.ErrorCode + Constants.NEWLINE;
            log.Error(extra + sqle.StackTrace);
            Debug.WriteLine(extra + sqle.StackTrace);
        }
        catch (Exception e)
        {
            log.Error("SQLServerdb.executeSelect - query: " + query.ToString());
            log.Error(e.StackTrace);
            Debug.WriteLine(e.StackTrace);
        }
        finally
        {
            // Always make sure result sets and statements are closed,
            // and the connection is returned to the pool
            if(cmd != null)
            {
                cmd.Dispose();
                cmd = null;
            }
            if (cmd2 != null)
            {
                cmd2.Dispose();
                cmd2 = null;
            }
            if (cmd3 != null)
            {
                cmd3.Dispose();
                cmd3 = null;
            }
            if (rdr != null)
            {
                rdr.Close();
                rdr.Dispose();
                rdr = null;
            }
            if (conn != null)
            {
                conn.Close();
                conn.Dispose();
                conn = null;
            }
        }

        return data;
    }//end executeSelect me

When you execute the COUNT command, the previous SqlDataReader is still open. This causes an error because as stated in MSDN

While the SqlDataReader is being used, the associated SqlConnection is busy serving the SqlDataReader, and no other operations can be performed on the SqlConnection other than closing it. This is the case until the Close method of the SqlDataReader is called. For example, you cannot retrieve output parameters until after you call Close

So, if this is the cause of your error you should add a rdr.Close before emitting another command on the same connection. (Or just add MultipleActiveResultSets =True to your connection string)

A SIDE BUT VERY IMPORTANT NOTE: Your architecture to create strings to execute is flawed. The SQL Injection is a dangerous possibility for every database related code. You should need to add Parameterized Queries in your tools of the trade.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM