/// <summary>
        /// <paramref name="sqlCommand"/> 를 이용하여, <see cref="Task{SqlDataReader}"/>를 반환받습니다.
        /// 받환받은 DataReader는 꼭 Dispose() 해 주어야 Connection이 닫힙니다.
        /// </summary>
        /// <param name="sqlDatabase">DAAB의 SQL Server용 Database</param>
        /// <param name="sqlCommand">실행할 sqlCommand 인스턴스</param>
        /// <param name="parameters">Command Parameters</param>
        /// <returns></returns>
        public static Task <SqlDataReader> ExecuteReaderAsync(this SqlDatabase sqlDatabase,
                                                              SqlCommand sqlCommand,
                                                              params IAdoParameter[] parameters)
        {
            sqlCommand.ShouldNotBeNull("sqlCommand");

            if (IsDebugEnabled)
            {
                log.Debug("ExecuteReader 를 비동기 방식으로 실행합니다... CommandText=[{0}], Parameters=[{1}]",
                          sqlCommand.CommandText, parameters.CollectionToString());
            }

            var newConnectionCreated = false;

            if (sqlCommand.Connection == null)
            {
                sqlCommand.Connection = SqlTool.CreateSqlConnection(sqlDatabase, ref newConnectionCreated);
            }

            if (parameters != null)
            {
                AdoTool.SetParameterValues(sqlDatabase, sqlCommand, parameters);
            }

            var commandBehavior = newConnectionCreated ? CommandBehavior.CloseConnection : CommandBehavior.Default;


            var tcs = new TaskCompletionSource <SqlDataReader>();

            sqlCommand.BeginExecuteReader(iar => {
                try {
                    tcs.TrySetResult(sqlCommand.EndExecuteReader(iar));
                }
                catch (Exception ex) {
                    tcs.TrySetException(ex);
                }
            },
                                          null,
                                          commandBehavior);

            return(tcs.Task);

            //! NOTE: FromAsync를 사용하지 못한 이유가 sqlCommand.BeginExecuteReader() 의 overloading이 많아서, 모호한 함수 호출 때문이다.

            //var ar = sqlCommand.BeginExecuteReader(commandBehavior);
            //return Task.Factory.StartNew(() => sqlCommand.EndExecuteReader(ar));

            //Task<SqlDataReader>.Factory.StartNew(state => sqlCommand.EndExecuteReader((IAsyncResult)state),
            //									 ar,
            //									 TaskCreationOptions.None);
        }
        /// <summary>
        /// <see cref="SqlCommand.ExecuteXmlReader"/> 를 비동기 방식으로 실행하는 <see cref="Task{XmlReader}"/> 를 빌드합니다.
        /// </summary>
        /// <param name="sqlDatabase">DAAB Database 인스턴스</param>
        /// <param name="sqlCommand">실행할 sqlCommand 인스턴스</param>
        /// <param name="disposeCommandWhenCompleted">작업 완료 후 command를 dispose할 것인가?</param>
        /// <param name="parameters">Command paramters</param>
        /// <returns>비동기 실행용 <see cref="Task{XmlReader}"/></returns>
        public static Task <XmlReader> ExecuteXmlReaderAsync(this SqlDatabase sqlDatabase,
                                                             SqlCommand sqlCommand,
                                                             bool disposeCommandWhenCompleted,
                                                             params IAdoParameter[] parameters)
        {
            sqlCommand.ShouldNotBeNull("sqlCommand");

            if (IsDebugEnabled)
            {
                log.Debug("sqlCommand.ExecuteXmlReader를 비동기 방식으로 실행합니다... CommandText=[{0}], parameters=[{1}]",
                          sqlCommand.CommandText, parameters.CollectionToString());
            }


            var newConnectionCreated = false;

            if (sqlCommand.Connection == null)
            {
                sqlCommand.Connection = SqlTool.CreateSqlConnection(sqlDatabase, ref newConnectionCreated);
            }

            if (parameters != null)
            {
                AdoTool.SetParameterValues(sqlDatabase, sqlCommand, parameters);
            }

            return
                (Task.Factory
                 .StartNew(() => sqlCommand.ExecuteXmlReader(), TaskCreationOptions.PreferFairness)
                 .ContinueWith(antecedent => {
                if (IsDebugEnabled)
                {
                    log.Debug("sqlCommand.ExecuteXmlReader를 비동기 방식으로 실행했습니다!!! CommandText=[{0}]",
                              sqlCommand.CommandText);
                }

                if (newConnectionCreated)
                {
                    AdoTool.ForceCloseConnection(sqlCommand);
                }

                if (disposeCommandWhenCompleted)
                {
                    With.TryAction(sqlCommand.Dispose);
                }

                return antecedent.Result;
            },
                               TaskContinuationOptions.ExecuteSynchronously));
        }
        /// <summary>
        /// <see cref="SqlCommand"/>을 ExecuteNonQuery 메소드로 비동기 실행을 하도록 하는 <see cref="Task{Int32}"/>를 빌드합니다.
        /// </summary>
        /// <param name="sqlDatabase">DAAB의 MS SQL Server용 Database 인스턴스</param>
        /// <param name="sqlCommand">실행할 SqlComnnad 인스턴스</param>
        /// <param name="parameters">파리미터 정보</param>
        /// <returns>실행에 영향을 받은 행의 수를 결과로 가지는 <see cref="Task{Int32}"/></returns>
        public static Task <int> ExecuteNonQueryAsync(this SqlDatabase sqlDatabase,
                                                      SqlCommand sqlCommand,
                                                      params IAdoParameter[] parameters)
        {
            sqlCommand.ShouldNotBeNull("sqlCommand");

            if (IsDebugEnabled)
            {
                log.Debug("sqlCommand.ExecuteNonQuery를 비동기 방식으로 실행합니다. CommandText=[{0}], Parameters=[{1}]",
                          sqlCommand.CommandText, sqlCommand.Parameters.CollectionToString());
            }

            var newConnectionCreated = false;

            if (sqlCommand.Connection == null)
            {
                sqlCommand.Connection = SqlTool.CreateSqlConnection(sqlDatabase, ref newConnectionCreated);
            }

            if (parameters != null)
            {
                AdoTool.SetParameterValues(sqlDatabase, sqlCommand, parameters);
            }

            //! NOTE: FromAsync 메소드에서는 TaskCreationOptions.None 만 가능하다.
            //
            return
                (Task <int> .Factory
                 .FromAsync(sqlCommand.BeginExecuteNonQuery,
                            sqlCommand.EndExecuteNonQuery,
                            null)
                 .ContinueWith(task => {
                if (newConnectionCreated)
                {
                    AdoTool.ForceCloseConnection(sqlCommand);
                }
                return task;
            },
                               TaskContinuationOptions.ExecuteSynchronously)
                 .Unwrap());
        }
        /// <summary>
        /// <paramref name="sqlCommand"/> 를 비동기 방식으로 실행하여, Scalar 값을 반환하는 <see cref="Task{Object}"/>를 빌드합니다.
        /// </summary>
        /// <param name="sqlDatabase">DAAB의 SQL Server용 Database</param>
        /// <param name="sqlCommand">실행할 sqlCommand 인스턴스</param>
        /// <param name="parameters">Command Parameters</param>
        /// <returns>결과 Scalar 값을 가지는 Task의 인스턴스</returns>
        public static Task <object> ExecuteScalarAsync(this SqlDatabase sqlDatabase,
                                                       SqlCommand sqlCommand,
                                                       params IAdoParameter[] parameters)
        {
            sqlCommand.ShouldNotBeNull("sqlCommand");

            if (IsDebugEnabled)
            {
                log.Debug("sqlCommand.ExecuteScalar 를 비동기 방식으로 실행합니다. CommandText=[{0}], Parameters=[{1}]",
                          sqlCommand.CommandText, parameters.CollectionToString());
            }

            var newConnectionCreated = false;

            if (sqlCommand.Connection == null)
            {
                sqlCommand.Connection = SqlTool.CreateSqlConnection(sqlDatabase, ref newConnectionCreated);
            }

            if (parameters != null)
            {
                AdoTool.SetParameterValues(sqlDatabase, sqlCommand, parameters);
            }

            return
                (Task.Factory
                 .StartNew(() => sqlCommand.ExecuteScalar())
                 .ContinueWith(task => {
                if (newConnectionCreated)
                {
                    AdoTool.ForceCloseConnection(sqlCommand);
                }

                return task;
            },
                               TaskContinuationOptions.ExecuteSynchronously)
                 .Unwrap());
        }