Пример #1
0
        /// <summary>
        /// Выполняет действие с экземпляром SqlCommand, созданным по подключению соответсвующему данному адаптеру.
        /// </summary>
        /// <param name="query">Текст команды.</param>
        /// <param name="executeCommandCode">Действие выполняемой с экземпляром SqlCommand.</param>
        /// <param name="sqlParameters">Параметры команды.</param>
        private void ExecuteCommandInternal(string query, ExecuteCommandCode executeCommandCode, params SqlParameter[] sqlParameters)
        {
            if (string.IsNullOrEmpty(query))
            {
                throw new ArgumentNullException("query");
            }
            if (executeCommandCode == null)
            {
                throw new ArgumentNullException("executeCommandCode");
            }

            //получаем текущую транзакцию из контекста.
            DBTransaction currentTransaction = DBTransaction.Current;

            //если sql-транзакция отсутствует, выполняем обычный запрос не в транзакции, используя общий коннект для всех вложенных комманд, если он имеется.
            //иначе - создаем открытый коннект, действующий в продолжение всей транзакции.
            if (currentTransaction == null || this.Connection.Context.IsSuppressContext)
            {
                //выполняем действие без Sql-транзакции.
                //создаем подключение, команду и выполняем запрос
                using (SqlConnection contextConnection = new SqlConnection(this.Connection.ConnectionString))
                {
                    contextConnection.Open();

                    //выполняем команду в рамках открытого подключения.
                    this.TryExecuteCommand(0, query, contextConnection, null, executeCommandCode, sqlParameters);
                }
            }
            else
            {
                //выполняем действие в Sql-транзакции.
                //инициализируем транзакцию данным подключением.
                currentTransaction.InitTransaction(this.Connection);

                //выполняем команду, используя подключение транзакции.
                this.TryExecuteCommand(0, query, currentTransaction.OpenedConnection, currentTransaction.OpenedTransaction, executeCommandCode, sqlParameters);

                //проверяем, что коннект не закрыт, для возможности выполнения следующих комманд при помощи данного коннекта.
                //если даже код до сюда не дойдет, то это не вызовет утечку ресурсов, поэтому блок try/finaly можно здесь не ставить.
                currentTransaction.CheckConnectionOpened();
            }
        }
Пример #2
0
        private void TryExecuteCommand(int tryCount, string query, SqlConnection contextConnection, SqlTransaction contextTransaction, ExecuteCommandCode executeCommandCode, params SqlParameter[] sqlParameters)
        {
            if (string.IsNullOrEmpty(query))
            {
                throw new ArgumentNullException("query");
            }
            if (contextConnection == null)
            {
                throw new ArgumentNullException("contextConnection");
            }
            if (executeCommandCode == null)
            {
                throw new ArgumentNullException("executeCommandCode");
            }

            //инициализируем текст команды.
            string cmdText = query;

            //если задана контекстная транзакция всегда задаем контекст БД,
            //поскольку после выполнения запроса в экземпляре SqlConnection свойство Database изменяется и становится отличным от Initial Catalog.
            if (contextTransaction != null)
            {
                cmdText = string.Format(@"USE [{0}]
{1}", this.Connection.DatabaseName, query);
            }

            try
            {
                using (SqlCommand cmd = new SqlCommand(cmdText, contextConnection))
                {
                    //если задана транзакция, назначаем ее.
                    if (contextTransaction != null)
                    {
                        cmd.Transaction = contextTransaction;
                    }

                    this.SetCommandTimeout(cmd);
                    if (sqlParameters != null)
                    {
                        foreach (SqlParameter parameter in sqlParameters)
                        {
                            if (parameter == null)
                            {
                                continue;
                            }

                            SqlParameter ensuredParam = this.EnsureParameter(tryCount, parameter);
                            cmd.Parameters.Add(ensuredParam);
                        }
                    }

                    //выполняем команду.
                    executeCommandCode(cmd);
                }
            }
            catch (Exception ex)
            {
                string errorText = ex.ToString().ToLower();
                //разрешаем перезапуск по взаимоблокировке только, если код выполняется вне транзакции.
                bool canRetry =
                    (errorText.Contains("deadlock") ||
                     errorText.Contains("взаимоблокировк")) &&
                    contextTransaction == null;
                if (!canRetry || tryCount == MaxTryCounts - 1)
                {
                    //формируем окончательную ошибку и отправляем её наверх.
                    Exception completedEx = new Exception(string.Format("Ошибка при выполнении запроса: {0}Не удалось выполнить запрос в базе данных {1} ***** {2} *****.", this.GetErrorsStack(ex), this.Connection.DisplayName, cmdText), ex);

                    //логируем ошибку, если не применяется логирование методом DBConnectionContext.ExecuteTransactionInternal.
                    if (!this.Connection.Context.IsExecuteTransactionContext)
                    {
                        this.Connection.Context.WriteEventLog(completedEx);
                    }

                    //отправляем ошибку.
                    throw completedEx;
                }
                else
                {
                    //делаем обработку взаимоблокировок: засыпаем поток, и пытаемся выполнить запрос еще раз.
                    Thread.Sleep(200);

                    //если запрос выполняется в транзакции, то обработку взаимоблокировки делаем вне транзакции.
                    using (SqlConnection suppressedConnection = new SqlConnection(this.Connection.ConnectionString))
                    {
                        suppressedConnection.Open();
                        this.TryExecuteCommand(tryCount + 1, query, suppressedConnection, null, executeCommandCode, sqlParameters);
                    }
                }
            }
        }
Пример #3
0
 /// <summary>
 /// Выполняет действие с экземпляром SqlCommand, созданным по подключению соответсвующему данному адаптеру.
 /// </summary>
 /// <param name="query">Текст команды.</param>
 /// <param name="executeCommandCode">Действие выполняемой с экземпляром SqlCommand.</param>
 /// <param name="sqlParameters">Параметры команды.</param>
 public void ExecuteCommand(string query, ExecuteCommandCode executeCommandCode, params SqlParameter[] sqlParameters)
 {
     this.ExecuteCommandInternal(query, executeCommandCode, sqlParameters);
 }