2014-09-28 2 views
0

Я запускаю метод, который выполняет запрос, а затем пытается выполнить другой запрос, прежде чем я закрою соединение. Первый запрос выполняет штраф, а второй вызывает:InvalidOperationException on SqlCommand.ExecuteScalar()

InvalidOperationException в методе SqlCommand.ExecuteScalar().

У меня было это бег безупречно раньше, но что-то изменилось, что я не могу отследить. Я тестирую, чтобы проверить, закрыто ли соединение или нет до выполнения запроса, но оно НЕ имеет значение null или не закрыто. Так что это меня смущает. У кого-нибудь есть идея, что происходит?

Запрос выполняется очень просто:

SELECT COUNT(*) 
FROM browsers; 

Я проверил это в SQL Server Management Studio с базой данных, и она работает просто отлично.

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 
+0

У вас есть MultipleActiveResultSets = True в вашей строке подключения? Когда вы выполняете вторую команду, читатель, открытый ранее, кажется, все еще открыт. Это NO-NO без включенной MARS – Steve

ответ

1

Когда вы выполняете команду COUNT, предыдущий SqlDataReader по-прежнему открыт. Это приводит к ошибке, потому что as stated in MSDN

В то время как SqlDataReader используется, связанная с SqlConnection является занята обслуживающей SqlDataReader, и никаких других операций не могут быть выполнены на SqlConnection, кроме его закрытия. Это так: до тех пор, пока не вызывается метод Close метода SqlDataReader. Например, вы не можете получить выходные параметры, пока после вызова Close

Так что, если это является причиной вашей ошибки вы должны добавить rdr.Close перед испусканием другой команды на том же соединении. (Или просто добавьте MultipleActiveResultSets = Верно для вашей строки подключения)

СТОРОНА, НО ОЧЕНЬ ВАЖНО ПРИМЕЧАНИЕ. Ваша архитектура для создания строк для выполнения является ошибочной. SQL Injection является опасной возможностью для каждого кода, связанного с базой данных. Вам нужно добавить Parameterized Queries в свои инструменты торговли.

+0

Так оно и было. Спасибо. Кроме того, спасибо за ссылки, я буду изучать их дальше и попытаться улучшить свой код. – Alan

Смежные вопросы