/// <summary> /// Copies the chunk. /// </summary> /// <param name="reader">The statistical reader.</param> /// <param name="bulkCopy">The bulk copy.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>An asynchronous completion token.</returns> private async Task CopyChunk(StatisticsDataReader reader, IBulkCopy bulkCopy, CancellationToken cancellationToken) { EventPublisher.Raise(new ChunkCopyingEvent { TargetName = this.target.Name, RowCount = reader.RowCount, ResultCount = reader.ResultCount, OperationId = this.operationId }); var chunkTimer = new Stopwatch(); chunkTimer.Start(); this.target.InitializeChunk(); await bulkCopy.WriteToServerAsync(reader, cancellationToken); chunkTimer.Stop(); this.target.ChunkComplete(); EventPublisher.Raise(new ChunkCopiedEvent { TargetName = this.target.Name, Duration = chunkTimer.Elapsed, RowCount = reader.RowCount, ResultCount = reader.ResultCount, OperationId = this.operationId }); }
/// <summary> /// Copies the data. /// </summary> /// <param name="sourceData">The source data.</param> /// <param name="bulkCopy">The bulk copy target.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>An asynchronous completion token.</returns> private async Task CopyData(IDataReader sourceData, IBulkCopy bulkCopy, CancellationToken cancellationToken) { var statisticalReader = new StatisticsDataReader(sourceData); do { try { await this.CopyChunk(statisticalReader, bulkCopy, cancellationToken); } catch (Exception ex) { var properties = ExtractErrorProperties(statisticalReader); EventPublisher.Raise(new OperationErrorEvent(this, ex, properties)); throw; } }while (!cancellationToken.IsCancellationRequested && statisticalReader.NextResult()); this.target.BatchComplete(); EventPublisher.Raise(new BatchCompleteEvent { Operation = this, Duration = this.timer.Elapsed, RowCount = statisticalReader.RowCount, ResultCount = statisticalReader.ResultCount }); }
/// <summary> /// Extracts the error properties. /// </summary> /// <param name="statisticalReader">The statistical reader.</param> /// <returns>A set of name value pair properties to help with diagnostics.</returns> private static IDictionary <string, string> ExtractErrorProperties(StatisticsDataReader statisticalReader) { var properties = new Dictionary <string, string>(); properties["_RowCount"] = statisticalReader.RowCount.ToString(CultureInfo.CurrentCulture); properties["_ResultCount"] = statisticalReader.ResultCount.ToString(CultureInfo.CurrentCulture); for (int i = 0; i < statisticalReader.FieldCount; ++i) { properties[statisticalReader.GetName(i)] = statisticalReader.GetValue(i).ToString(); } return(properties); }
/// <summary> /// Checks the row count differences. /// </summary> /// <param name="expectedResults">The expected results.</param> /// <param name="actualValues">The actual values.</param> /// <returns>A sequence of row count difference elements.</returns> private IEnumerable <XElement> CheckRowCountDifferences(StatisticsDataReader expectedResults, StatisticsDataReader actualValues) { while (expectedResults.Read()) { } while (actualValues.Read()) { } if (expectedResults.RowCount != actualValues.RowCount) { ++this.differences; yield return (new XElement( "RowCountDifference", new XAttribute("Expected", expectedResults.RowCount), new XAttribute("Actual", actualValues.RowCount))); } }
public override ValidationResult Validate(ValidationContext context) { using (IDbConnection expectedConnection = this.expectedConnectionFactory.CreateConnection()) using (IDbConnection actualsConnection = this.ConnectionFactory.CreateConnection()) { expectedConnection.Open(); actualsConnection.Open(); var expectedCommand = expectedConnection.CreateCommand(); expectedCommand.CommandText = this.expectedQuery; expectedCommand.CommandTimeout = 600; var actualsCommand = actualsConnection.CreateCommand(); actualsCommand.CommandText = this.actualsQuery; actualsCommand.CommandTimeout = 600; var additionalInformation = new List <XElement>(); additionalInformation.Add( new XElement("ExpectedConnection", new XCData(this.expectedConnectionFactory.Name))); additionalInformation.Add( new XElement("ExpectedQuery", new XCData(this.expectedQuery))); additionalInformation.Add( new XElement("ActualsQuery", new XCData(this.actualsQuery))); using (var expectedResults = new StatisticsDataReader(expectedCommand.ExecuteReader())) using (var actualValues = new StatisticsDataReader(actualsCommand.ExecuteReader())) { bool checkExtraRows = true; while (expectedResults.Read() && actualValues.Read()) { if (expectedResults.FieldCount != actualValues.FieldCount) { // The results are different since they have a differing // number of columns. additionalInformation.Add( new XElement( "ColumnCountDifference", new XAttribute("Expected", expectedResults.FieldCount), new XAttribute("Actual", actualValues.FieldCount))); ++this.differences; checkExtraRows = false; break; } var rowDifferences = this.CheckRowDifferences(expectedResults, actualValues) .ToArray(); if (rowDifferences.Length > 0) { additionalInformation.Add(new XElement("Row", rowDifferences)); } } if (checkExtraRows) { additionalInformation.AddRange( this.CheckRowCountDifferences(expectedResults, actualValues)); } } return(new ValidationResult { Value = this.differences, Metadata = this.Metadata, Status = this.differences <= this.Metadata.Goal ? 1 : -1, CheckName = this.Name, CheckType = this.CheckType, EntityName = this.entityName, AdditionalInformation = new XElement("AdditionalInformation", additionalInformation) }); } }