2015-09-21 2 views
3

Я использую .Net Compact 3.5 Windows 7 CE.System.ArgumentException Значение не входит в ожидаемый диапазон, проблема SQL

У меня есть приложение с примерно 50 пользователями, у меня есть настройка, чтобы я получал электронное письмо каждый раз, когда транзакция базы данных терпела неудачу, с запросом.

Каждый так часто я хотел бы получить письмо с трассировки стека, который начинается так:

System.ArgumentException: Value does not fall within the expected range.
at System.Data.SqlClient.SqlParameterCollection.Validate(Int32 index, SqlParameter value)
at System.Data.SqlClient.SqlParameterCollection.AddWithoutEvents(SqlParameter value)
at System.Data.SqlClient.SqlParameterCollection.Add(SqlParameter value)
at MedWMS.Database.startSqlConnection(String query, SqlParameter[] parameters, SqlConnection connection, SqlCommand cmd)
at MedWMS.Database.<>c__DisplayClasse.b__8()
at MedWMS.Database.retry(Action action)
at MedWMS.Database.executeNonQuery(String query, SqlParameter[] parameters, String connectionString)...

В SQL запрос, который вызывает этот вопрос не всегда то же самое. Я запускаю те же запросы секунд после получения электронной почты в SQL Server Management Studio без проблем.

Я хотел бы знать, почему это может произойти. Это мой первый вопрос о SO, поэтому, пожалуйста, дайте мне знать, если я что-то делаю неправильно. Я был бы рад ответить на любые вопросы, чтобы предоставить более подробную информацию.

Это образец кода, который может вызвать эту ошибку:

SqlParameter[] parameters = new SqlParameter[1]; 
parameters[0] = new SqlParameter("@salesOrder", this.salesOrderNumber); 

string query = @" 
       Select InvTermsOverride from SorMaster where SalesOrder = Convert(int, @salesOrder) and InvTermsOverride = '07' --07 is for COD"; 

DataTable dt = Database.executeSelectQuery(query, parameters, Country.getCurrent().getSysproConnectionStrReportServer()); 

Это запрос, который фактически получает передается:

Select InvTermsOverride from SorMaster where SalesOrder = Convert(int, '000000001138325') and InvTermsOverride = '07' --07 is for COD 

Вот соответствующие методы из Database класса:

public static DataTable executeSelectQuery(String query, SqlParameter[] parameters, string connectionString) 
{ 
    DataTable dt = new DataTable(); 

    using (SqlConnection connection = new SqlConnection(connectionString)) 
    { 
     SqlCommand cmd = null; 

     try 
     { 
      retry(() => 
      { 
       cmd = startSqlConnection(query, parameters, connection, cmd); 
       using (SqlDataReader reader = cmd.ExecuteReader()) 
       { 
        dt.Load(reader); 
       } 
      }); 
     } 
     catch (Exception ex) 
     { 
      onDbConnectionCatch(cmd, ex); 
     } 
     finally 
     { 
      cmd.Dispose(); 
      connection.Close(); 
     } 
    } 

    return dt; 
} 

public static void executeNonQuery(String query, SqlParameter[] parameters, string connectionString) 
{ 
    using (SqlConnection connection = new SqlConnection(connectionString)) 
    { 
     SqlCommand cmd = null; 

     try 
     { 
      retry(() => 
      { 
       cmd = startSqlConnection(query, parameters, connection, cmd); 
       cmd.ExecuteNonQuery(); 
      }); 
     } 
     catch (Exception ex) 
     { 
      onDbConnectionCatch(cmd, ex); 
     } 
     finally 
     { 
      cmd.Dispose(); 
      connection.Close(); 
     } 
    } 
} 

private static void retry(Action action) 
{ 
    int retryCount = 3; 
    int retryInterval = 1000; 
    Exception lastException = null; 

    for (int retry = 0; retry < retryCount; retry++) 
    { 
     try 
     { 
      if (retry > 0) 
       System.Threading.Thread.Sleep(retryInterval); 
      action(); 

      lastException = null; 
      return; 
     } 
     catch (Exception ex) 
     { 
      lastException = ex; 
     } 
    } 

    if (lastException != null) 
    { 
     throw lastException; 
    } 
} 

private static SqlCommand startSqlConnection(String query, SqlParameter[] parameters, SqlConnection connection, SqlCommand cmd) 
{ 
    if (connection.State != ConnectionState.Open) 
    { 
     connection.Open(); 
    } 

    cmd = new SqlCommand(query, connection); 

    if (parameters != null) 
    { 
     foreach (SqlParameter sp in parameters) 
     { 
      if (sp != null) 
      { 
       cmd.Parameters.Add(sp); 
      } 
     } 
    } 

    return cmd; 
} 

private static void onDbConnectionCatch(SqlCommand cmd, Exception ex) 
{ 
    try 
    { 
     new BigButtonMessageBox("", "Unable connect to database").ShowDialog(); 
     sendEmailWithSqlQuery(cmd, ex); 
    } 
    catch 
    { 
    } 
} 

private static void sendEmailWithSqlQuery(SqlCommand cmd, Exception ex) 
{ 
    string query2 = "cmd was null"; 

    if (cmd != null) 
    { 
     query2 = cmd.CommandText; 

     foreach (SqlParameter p in cmd.Parameters) 
     { 
      query2 = query2.Replace(p.ParameterName, "'" + p.Value.ToString() + "'"); 
     } 
    } 

    InternetTools.sendEmail("DB ERROR", ex.ToString() + "\r\n" + query2); 
} 
+0

пожалуйста, показать, что передается! –

+0

Я добавил запрос и параметры – BiggerD

+0

Я добавил запрос, который был отправлен «Выберите InvTermsOverride из SorMaster, где SalesOrder = Convert (int, '000000001138325') и InvTermsOverride = '07' --07 для COD", но это же запрос работает в студии управления SQL – BiggerD

ответ

1

У меня была такая же проблема, как у Can't solve "Sqlparameter is already contained by another SqlparameterCollection"

По какой-то причине SQL CE имеет другую ошибку.

Из-за моего метода повторных попыток, я не мог повторно использовать объект SqlParameter, до сих пор не знаю, почему это не разрешено

В любом случае я изменил

cmd.Parameters.Add(sp); 

в

cmd.Parameters.Add(sp.ParameterName, sp.Value);