Esempio n. 1
0
        public static List <SqlTransactionBatch> GroupByTransaction(IEnumerable <string> sqlScripts)
        {
            sqlScripts = sqlScripts.Where(s => !string.IsNullOrWhiteSpace(s.Replace(SqlUtility.NoTransactionTag, "")));
            var batches = CsUtility.GroupItemsKeepOrdering(sqlScripts, SqlUtility.ScriptSupportsTransaction);

            return(batches.Select(batch => new SqlTransactionBatch(batch.Items)
            {
                UseTransacion = batch.Key
            }).ToList());
        }
Esempio n. 2
0
        /// <summary>
        /// 1. Splits the scripts by the SQL batch delimiter ("GO", for Microsoft SQL Server). See <see cref="SqlUtility.SplitBatches(string)"/>.
        /// 2. Detects and applies the transaction usage tag. See <see cref="SqlUtility.NoTransactionTag"/> and <see cref="SqlUtility.ScriptSupportsTransaction(string)"/>.
        /// 3. Reports progress (Info level) after each minute.
        /// 4. Prefixes each SQL script with a comment containing the script's name.
        /// </summary>
        public void Execute(IEnumerable <SqlScript> sqlScripts)
        {
            var scriptParts = sqlScripts
                              .SelectMany(script => script.IsBatch
                    ? SqlUtility.SplitBatches(script.Sql).Select(scriptPart => new SqlScript {
                Name = script.Name, Sql = scriptPart, IsBatch = false
            })
                    : new[] { script })
                              .Where(script => !string.IsNullOrWhiteSpace(script.Sql));

            var sqlBatches = CsUtility.GroupItemsKeepOrdering(scriptParts, script => SqlUtility.ScriptSupportsTransaction(script.Sql))
                             .Select(group => new
            {
                UseTransaction = group.Key,
                // The empty NoTransactionTag script is used by the DatabaseGenerator to split transactions.
                // This is why there scrips are removed *after* grouping
                Scripts = group.Items.Where(s => !string.Equals(s.Sql, SqlUtility.NoTransactionTag, StringComparison.Ordinal)).ToList()
            })
                             .Where(group => group.Scripts.Count() > 0) // Cleanup after removing the empty NoTransactionTag scripts.
                             .ToList();

            _logger.Trace(() => "SqlBatches: " + string.Join(", ", sqlBatches.Select(b => $"{(b.UseTransaction ? "tran" : "notran")} {b.Scripts.Count()}")));

            int totalCount           = sqlBatches.Sum(b => b.Scripts.Count);
            int previousBatchesCount = 0;
            var startTime            = DateTime.Now;
            var lastReportTime       = startTime;

            foreach (var sqlBatch in sqlBatches)
            {
                Action <int> reportProgress = currentBatchCount =>
                {
                    var now           = DateTime.Now;
                    int executedCount = previousBatchesCount + currentBatchCount + 1;

                    if (now.Subtract(lastReportTime).TotalMilliseconds > _reportDelayMs &&
                        executedCount < totalCount)    // No need to report progress if the work is done.
                    {
                        double estimatedTotalMs = now.Subtract(startTime).TotalMilliseconds / executedCount * totalCount;
                        var    remainingTime    = startTime.AddMilliseconds(estimatedTotalMs).Subtract(now);
                        _logger.Info($"Executed {executedCount} / {totalCount} SQL scripts. {(remainingTime.TotalMinutes).ToString("f2")} minutes remaining.");
                        lastReportTime = now;
                    }
                };

                var scriptsWithName = sqlBatch.Scripts
                                      .Select(script => string.IsNullOrEmpty(script.Name)
                        ? script.Sql
                        : "--Name: " + script.Name.Replace("\r", " ").Replace("\n", " ") + "\r\n" + script.Sql);

                _sqlExecuter.ExecuteSql(scriptsWithName, sqlBatch.UseTransaction, null, reportProgress);

                previousBatchesCount += sqlBatch.Scripts.Count;
            }
        }