/// <summary>
        /// Asynchronously executes the given operation using the <paramref name="operationData"/> values
        /// as input to the operation.
        /// </summary>
        /// <param name="operationName">Operation to execute.</param>
        /// <param name="operationData">Input data for operation.</param>
        /// <returns>Task encapsulating storage results object.</returns>
        public virtual Task <IStoreResults> ExecuteOperationAsync(string operationName, XElement operationData)
        {
            return(SqlUtils.WithSqlExceptionHandlingAsync <IStoreResults>(async() =>
            {
                SqlResults results = new SqlResults();

                using (SqlCommand cmd = _conn.CreateCommand())
                    using (XmlReader input = operationData.CreateReader())
                    {
                        cmd.Transaction = _tran;
                        cmd.CommandText = operationName;
                        cmd.CommandType = CommandType.StoredProcedure;

                        SqlUtils.AddCommandParameter(cmd, "@input", SqlDbType.Xml, ParameterDirection.Input, -1, new SqlXml(input));

                        SqlParameter result = SqlUtils.AddCommandParameter(cmd, "@result", SqlDbType.Int, ParameterDirection.Output, 0, 0);

                        using (SqlDataReader reader = await cmd.ExecuteReaderAsync().ConfigureAwait(false))
                        {
                            await results.FetchAsync(reader).ConfigureAwait(false);
                        }

                        // Output parameter will be used to specify the outcome.
                        results.Result = (StoreResult)result.Value;
                    }

                return results;
            }));
        }
        /// <summary>
        /// Asynchronously performs validation that the local representation is as 
        /// up-to-date as the representation on the backing data store.
        /// </summary>
        /// <param name="conn">Connection used for validation.</param>
        /// <param name="manager">ShardMapManager reference.</param>
        /// <param name="shardMap">Shard map for the shard.</param>
        /// <param name="shard">Shard to validate.</param>
        /// <returns>A task to await validation completion</returns>
        internal static async Task ValidateShardAsync(
            SqlConnection conn,
            ShardMapManager manager,
            IStoreShardMap shardMap,
            IStoreShard shard
            )
        {
            Stopwatch stopwatch = Stopwatch.StartNew();

            SqlResults lsmResult = new SqlResults();

            XElement xeValidate = StoreOperationRequestBuilder.ValidateShardLocal(shardMap.Id, shard.Id, shard.Version);

            using (SqlCommand cmd = conn.CreateCommand())
            using (XmlReader input = xeValidate.CreateReader())
            {
                cmd.CommandText = StoreOperationRequestBuilder.SpValidateShardLocal;
                cmd.CommandType = CommandType.StoredProcedure;

                SqlUtils.AddCommandParameter(
                    cmd,
                    "@input",
                    SqlDbType.Xml,
                    ParameterDirection.Input,
                    0,
                    new SqlXml(input));

                SqlParameter resultParam = SqlUtils.AddCommandParameter(
                    cmd,
                    "@result",
                    SqlDbType.Int,
                    ParameterDirection.Output,
                    0,
                    0);

                using (SqlDataReader reader = await cmd.ExecuteReaderAsync())
                {
                    await lsmResult.FetchAsync(reader);
                }

                // Output parameter will be used to specify the outcome.
                lsmResult.Result = (StoreResult)resultParam.Value;
            }

            stopwatch.Stop();

            Tracer.TraceInfo(
                TraceSourceConstants.ComponentNames.Shard,
                "ValidateShardAsync",
                "Complete; Shard: {0}; Connection: {1}; Result: {2}; Duration: {3}",
                shard.Location,
                conn.ConnectionString,
                lsmResult.Result,
                stopwatch.Elapsed);

            if (lsmResult.Result != StoreResult.Success)
            {
                if (lsmResult.Result == StoreResult.ShardMapDoesNotExist)
                {
                    manager.Cache.DeleteShardMap(shardMap);
                }

                // Possible errors are:
                // StoreResult.ShardMapDoesNotExist
                // StoreResult.ShardDoesNotExist
                // StoreResult.ShardVersionMismatch
                // StoreResult.StoreVersionMismatch
                // StoreResult.MissingParametersForStoredProcedure
                throw StoreOperationErrorHandler.OnValidationErrorLocal(
                    lsmResult,
                    shardMap,
                    shard.Location,
                    "ValidateShardAsync",
                    StoreOperationRequestBuilder.SpValidateShardLocal);
            }
        }
        /// <summary>
        /// Asynchronously executes the given operation using the <paramref name="operationData"/> values
        /// as input to the operation.
        /// </summary>
        /// <param name="operationName">Operation to execute.</param>
        /// <param name="operationData">Input data for operation.</param>
        /// <returns>Task encapsulating storage results object.</returns>
        public virtual async Task<IStoreResults> ExecuteOperationAsync(string operationName, XElement operationData)
        {
            return await SqlUtils.WithSqlExceptionHandlingAsync<IStoreResults>(async () =>
            {
                SqlResults results = new SqlResults();

                using (SqlCommand cmd = _conn.CreateCommand())
                using (XmlReader input = operationData.CreateReader())
                {
                    cmd.Transaction = _tran;
                    cmd.CommandText = operationName;
                    cmd.CommandType = CommandType.StoredProcedure;

                    SqlUtils.AddCommandParameter(cmd, "@input", SqlDbType.Xml, ParameterDirection.Input, -1, new SqlXml(input));

                    SqlParameter result = SqlUtils.AddCommandParameter(cmd, "@result", SqlDbType.Int, ParameterDirection.Output, 0, 0);

                    using (SqlDataReader reader = await cmd.ExecuteReaderAsync())
                    {
                        await results.FetchAsync(reader);
                    }

                    // Output parameter will be used to specify the outcome.
                    results.Result = (StoreResult)result.Value;
                }

                return results;
            });
        }
        /// <summary>
        /// Asynchronously performs validation that the local representation is as
        /// up-to-date as the representation on the backing data store.
        /// </summary>
        /// <param name="conn">Connection used for validation.</param>
        /// <param name="manager">ShardMapManager reference.</param>
        /// <param name="shardMap">Shard map for the shard.</param>
        /// <param name="shard">Shard to validate.</param>
        /// <returns>A task to await validation completion</returns>
        internal static async Task ValidateShardAsync(
            SqlConnection conn,
            ShardMapManager manager,
            IStoreShardMap shardMap,
            IStoreShard shard
            )
        {
            Stopwatch stopwatch = Stopwatch.StartNew();

            SqlResults lsmResult = new SqlResults();

            XElement xeValidate = StoreOperationRequestBuilder.ValidateShardLocal(shardMap.Id, shard.Id, shard.Version);

            using (SqlCommand cmd = conn.CreateCommand())
                using (XmlReader input = xeValidate.CreateReader())
                {
                    cmd.CommandText = StoreOperationRequestBuilder.SpValidateShardLocal;
                    cmd.CommandType = CommandType.StoredProcedure;

                    SqlUtils.AddCommandParameter(
                        cmd,
                        "@input",
                        SqlDbType.Xml,
                        ParameterDirection.Input,
                        0,
                        new SqlXml(input));

                    SqlParameter resultParam = SqlUtils.AddCommandParameter(
                        cmd,
                        "@result",
                        SqlDbType.Int,
                        ParameterDirection.Output,
                        0,
                        0);

                    using (SqlDataReader reader = await cmd.ExecuteReaderAsync())
                    {
                        await lsmResult.FetchAsync(reader);
                    }

                    // Output parameter will be used to specify the outcome.
                    lsmResult.Result = (StoreResult)resultParam.Value;
                }

            stopwatch.Stop();

            Tracer.TraceInfo(
                TraceSourceConstants.ComponentNames.Shard,
                "ValidateShardAsync",
                "Complete; Shard: {0}; Connection: {1}; Result: {2}; Duration: {3}",
                shard.Location,
                conn.ConnectionString,
                lsmResult.Result,
                stopwatch.Elapsed);

            if (lsmResult.Result != StoreResult.Success)
            {
                if (lsmResult.Result == StoreResult.ShardMapDoesNotExist)
                {
                    manager.Cache.DeleteShardMap(shardMap);
                }

                // Possible errors are:
                // StoreResult.ShardMapDoesNotExist
                // StoreResult.ShardDoesNotExist
                // StoreResult.ShardVersionMismatch
                // StoreResult.StoreVersionMismatch
                // StoreResult.MissingParametersForStoredProcedure
                throw StoreOperationErrorHandler.OnValidationErrorLocal(
                          lsmResult,
                          shardMap,
                          shard.Location,
                          "ValidateShardAsync",
                          StoreOperationRequestBuilder.SpValidateShardLocal);
            }
        }