ExecuteScalar Указанное приведение не является допустимым исключением

Следующая строка кода иногда приводит к исключению "Указанное приведение недействительно":

public static object Select(string sql, OleDbTransaction dbt)
{
  try
  {
     OleDbCommand cmd = new OleDbCommand(sql, lib.dbc, dbt);
     object obj = cmd.ExecuteScalar(); /* <- this is what fails */
     return obj;
  }
  catch (Exception ex)
  {
    /* deleted code - error message to the user */
    return null;
  }
}

Эта функция выполняется в программе несколько раз, прежде чем произойдет сбой. Если происходит сбой только тогда, когда он выполняется в новом потоке выполнения, а затем только иногда. Когда я вызываю часть программы, которая выполняет обработку в потоке, и она вызывает эту функцию, либо она работает все время (=> я нажимаю кнопку, она выполняется, ошибки нет, я нажимаю и выполняю снова и снова.. .), или это никогда не работает (=> я нажимаю кнопку и выполняю, исключение, я нажимаю и снова выполняю, снова исключение...).

lib.dbc -> статическая переменная типа OleDbConnection инициализируется только при запуске программы и очень часто используется в коде, допустима

Я понятия не имею, как его отлаживать дальше, и, прежде всего, какое присваивание переменной типа object может привести к ошибке? ExecuteScalar должен возвращать объект или ноль. Я использую базу данных Jet (MS Access).

В исключении я нахожу эту трассировку стека, может быть, это поможет:

at System.Data.OleDb.OleDbConnection.IOpenRowset()
at System.Data.OleDb.OleDbCommand.ExecuteTableDirect(CommandBehavior behavior, Object& executeResult)
at System.Data.OleDb.OleDbCommand.ExecuteCommand(CommandBehavior behavior, Object& executeResult)
at System.Data.OleDb.OleDbCommand.ExecuteReaderInternal(CommandBehavior behavior, String method)
at System.Data.OleDb.OleDbCommand.ExecuteScalar()
at FK.sql.Select(String sql, OleDbTransaction dbt)

person Marko    schedule 15.02.2014    source источник
comment
При чем здесь SQL? Вы фактически выдаете запрос, возвращающий единственное значение?   -  person Jon Skeet    schedule 15.02.2014
comment
Вы используете одно и то же соединение в нескольких потоках? ADO.NET не предназначен для этого. @JonSkeet ExecuteScalar возвращает первый столбец первой строки в результирующем наборе или нулевую ссылку, если результирующий набор пуст.   -  person C.Evenhuis    schedule 15.02.2014
comment
@C.Evenhuis: Хороший вопрос. Проблема с резьбой вполне может быть. По-прежнему не рекомендуется использовать ExecuteScalar для результатов с более чем одним столбцом/строкой IMO, но это не должно вызывать эту ошибку.   -  person Jon Skeet    schedule 15.02.2014
comment
SQL всегда выбирает .... То, что он возвращает, не должно иметь значения, это может привести только к логическим ошибкам, поскольку функция представляет собой оболочку, созданную для управления любым результатом SELECT. Что касается многопоточности, у меня есть основной поток, который для этого конкретного случая (длительное выполнение) порождает 2 других потока - 1 поток обработки SQL и 1 диалоговый поток. Я нашел некоторую информацию о том, что мне может понадобиться ApartmentState = ApartmentState.MTA для моих потоков, я мало что знаю об этом. В любой момент только 1 поток выполняет SQL-запросы. Моя функция возвращает одно значение или ноль, это ее работа.   -  person Marko    schedule 15.02.2014


Ответы (2)


Если происходит сбой только тогда, когда он выполняется в новом потоке выполнения, и то только иногда.

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

Не делайте этого: вместо этого создавайте новое соединение каждый раз, когда вы хотите получить доступ к базе данных: пул соединений означает, что это будет эффективно.

person Joe    schedule 15.02.2014
comment
Да, я делюсь подключением к БД, понятия не имел, что в многопоточной среде это вызовет такой хаос. Когда я не разделяю соединение между потоками, мне не удалось воспроизвести ошибку. Спасибо! - person Marko; 16.02.2014

Попробуйте это, просто как диагностический инструмент:

public static object Select(string sql, OleDbTransaction dbt)
{
  try
  {
     using (OleDbConnection con = new OleDbConnection(lib.dbc.ConnectionString))
     using (OleDbCommand cmd = new OleDbCommand(sql, con, dbt))
     {
         object obj = cmd.ExecuteScalar();
         return obj;
     }
  }
  catch (Exception ex)
  {
    /* deleted code - error message to the user */
    return null;
  }
}

Это может помочь определить, есть ли у вас проблема с потоками.

person John Saunders    schedule 15.02.2014