/// <summary> /// Creates a clone of the database using another SqlAgent. /// </summary> /// <param name="cloneManager">an SQL schema manager to use when creating clone database</param> /// <param name="schemaToUse">a database schema to use (enforce), /// if null the schema ir read from the database cloned</param> /// <param name="ct">a cancelation token (if any)</param> /// <param name="progress">a progress callback (if any)</param> public async Task CloneDatabase(SchemaManagerBase cloneManager, DbSchema schemaToUse, IProgress <DbCloneProgressArgs> progress, CancellationToken ct) { if (cloneManager.IsNull()) { throw new ArgumentNullException(nameof(cloneManager)); } progress?.Report(new DbCloneProgressArgs(DbCloneProgressArgs.Stage.FetchingSchema, string.Empty, 0)); if (schemaToUse.IsNull()) { schemaToUse = await GetDbSchemaAsync(ct).ConfigureAwait(false); } if (CloneCanceled(progress, ct)) { return; } progress?.Report(new DbCloneProgressArgs(DbCloneProgressArgs.Stage.CreatingSchema, string.Empty, 0)); await cloneManager.CreateDatabaseAsync(schemaToUse).ConfigureAwait(false); if (CloneCanceled(progress, ct)) { return; } await cloneManager.Agent.ExecuteInTransactionAsync(async (cancellationToken) => { await cloneManager.DisableForeignKeysForCurrentTransactionAsync().ConfigureAwait(false); await CopyData(schemaToUse, cloneManager, progress, cancellationToken).ConfigureAwait(false); }, ct).ConfigureAwait(false); if (!ct.IsCancellationRequested) { progress?.Report( new DbCloneProgressArgs(DbCloneProgressArgs.Stage.Completed, string.Empty, 100)); } }
/// <summary> /// Invokes protected <see cref="InsertTableData">InsertTableData</see> /// method on target SqlAgent. Used to bypass cross instance protected method /// access limitation. /// </summary> /// <param name="target">the SqlAgent to invoke the <see cref="InsertTableData">InsertTableData</see> /// method on</param> /// <param name="table">a schema of the table to insert the data to</param> /// <param name="reader">an IDataReader to read the table data from</param> /// <remarks>Required for <see cref="CloneDatabase">CloneDatabase</see> infrastructure. /// The insert is performed using a transaction that is already initiated by the /// <see cref="CloneDatabase">CloneDatabase</see>.</remarks> protected static Task <long> CallInsertTableDataAsync(SchemaManagerBase target, DbTableSchema table, IDataReader reader, long totalRowCount, long currentRow, int currentProgress, IProgress <DbCloneProgressArgs> progress, CancellationToken ct) { return(target.InsertTableDataAsync(table, reader, totalRowCount, currentRow, currentProgress, progress, ct)); }
/// <summary> /// Copies table data from the current SqlAgent instance to the target SqlAgent instance. /// </summary> /// <param name="schema">a schema of the database to copy the data</param> /// <param name="targetManager">the target Sql schema manager to copy the data to</param> /// <remarks>Required for <see cref="CloneDatabase">CloneDatabase</see> infrastructure. /// Basicaly iterates tables, selects data, creates an IDataReader for the table and passes it to the /// <see cref="InsertTableData">InsertTableData</see> method of the target SqlAgent.</remarks> protected abstract Task CopyData(DbSchema schema, SchemaManagerBase targetManager, IProgress <DbCloneProgressArgs> progress, CancellationToken ct);