/// <summary> /// Provision the local database based on the schema parameter, and the provision enumeration /// </summary> /// <param name="schema">Schema to be applied to the database managed by the orchestrator, through the provider.</param> /// <param name="provision">Provision enumeration to determine which components to apply</param> /// <param name="clientScopeInfo">client scope. Will be saved once provision is done</param> /// <returns>Full schema with table and columns properties</returns> public virtual Task <SyncSet> ProvisionAsync(SyncSet schema, SyncProvision provision, bool overwrite = false, ScopeInfo clientScopeInfo = null, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null) => RunInTransactionAsync(SyncStage.Provisioning, async(ctx, connection, transaction) => { // Check incompatibility with the flags if (provision.HasFlag(SyncProvision.ServerHistoryScope) || provision.HasFlag(SyncProvision.ServerScope)) { throw new InvalidProvisionForLocalOrchestratorException(); } // Get server scope if not supplied if (clientScopeInfo == null) { var scopeBuilder = this.GetScopeBuilder(this.Options.ScopeInfoTableName); var exists = await this.InternalExistsScopeInfoTableAsync(ctx, DbScopeType.Client, scopeBuilder, connection, transaction, cancellationToken, progress).ConfigureAwait(false); if (exists) { clientScopeInfo = await this.InternalGetScopeAsync <ScopeInfo>(ctx, DbScopeType.Client, this.ScopeName, scopeBuilder, connection, transaction, cancellationToken, progress).ConfigureAwait(false); } } schema = await InternalProvisionAsync(ctx, overwrite, schema, this.Setup, provision, clientScopeInfo, connection, transaction, cancellationToken, progress).ConfigureAwait(false); return(schema); }, connection, transaction, cancellationToken);
public DeprovisioningArgs(SyncContext context, SyncProvision provision, SyncSetup setup, DbConnection connection, DbTransaction transaction) : base(context, connection, transaction) { Provision = provision; Setup = setup; }
public ProvisioningArgs(SyncContext context, SyncProvision provision, SyncSet schema, DbConnection connection, DbTransaction transaction) : base(context, connection, transaction) { Provision = provision; Schema = schema; }
/// <summary> /// Deprovision the orchestrator database based the provision enumeration /// </summary> public virtual async Task <bool> DeprovisionAsync(string scopeName, SyncProvision provision = default, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null) { var context = new SyncContext(Guid.NewGuid(), scopeName); try { if (provision == default) { provision = SyncProvision.StoredProcedures | SyncProvision.Triggers; } await using var runner = await this.GetConnectionAsync(context, SyncMode.Writing, SyncStage.Deprovisioning, connection, transaction, cancellationToken, progress).ConfigureAwait(false); // get client scope ClientScopeInfo clientScopeInfo; (context, clientScopeInfo) = await this.InternalLoadClientScopeInfoAsync(context, runner.Connection, runner.Transaction, cancellationToken, progress).ConfigureAwait(false); bool isDeprovisioned; (context, isDeprovisioned) = await InternalDeprovisionAsync(clientScopeInfo, context, provision, runner.Connection, runner.Transaction, cancellationToken, progress).ConfigureAwait(false); await runner.CommitAsync().ConfigureAwait(false); return(isDeprovisioned); } catch (Exception ex) { throw GetSyncError(context, ex); } }
public DatabaseProvisionedArgs(SyncContext context, SyncProvision provision, SyncSet schema, DbConnection connection = null, DbTransaction transaction = null) : base(context, connection, transaction) { Provision = provision; Schema = schema; }
/// <summary> /// Deprovision table /// </summary> public async Task DropAsync(SyncProvision provision, DbConnection connection, DbTransaction transaction = null) { var alreadyOpened = connection.State != ConnectionState.Closed; if (!alreadyOpened) { await connection.OpenAsync().ConfigureAwait(false); } if (provision.HasFlag(SyncProvision.StoredProcedures)) { await this.DropStoredProceduresAsync(connection, transaction).ConfigureAwait(false); } if (provision.HasFlag(SyncProvision.Triggers)) { await this.DropTriggersAsync(connection, transaction).ConfigureAwait(false); } if (provision.HasFlag(SyncProvision.TrackingTable)) { await this.DropTrackingTableAsync(connection, transaction).ConfigureAwait(false); } if (provision.HasFlag(SyncProvision.Table)) { await this.DropTableAsync(connection, transaction).ConfigureAwait(false); } if (!alreadyOpened) { connection.Close(); } }
/// <summary> /// Deprovision the orchestrator database based on the Setup table argument, and the provision enumeration /// </summary> /// <param name="provision">Provision enumeration to determine which components to deprovision</param> public virtual Task DeprovisionAsync(SetupTable table, SyncProvision provision, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null) { var setup = new SyncSetup(); setup.Tables.Add(table); // using a fake SyncTable based on oldSetup, since we don't need columns, but we need to have the filters var schemaTable = new SyncTable(table.TableName, table.SchemaName); // Create a temporary SyncSet for attaching to the schemaTable var tmpSchema = new SyncSet(); // Add this table to schema tmpSchema.Tables.Add(schemaTable); tmpSchema.EnsureSchema(); // copy filters from old setup foreach (var filter in this.Setup.Filters) { tmpSchema.Filters.Add(filter); } return(this.DeprovisionAsync(tmpSchema, provision, connection, transaction, cancellationToken, progress)); }
/// <summary> /// Deprovision the orchestrator database based on the Setup table argument, and the provision enumeration /// </summary> /// <param name="provision">Provision enumeration to determine which components to deprovision</param> public virtual Task DeprovisionAsync(SetupTable table, SyncProvision provision, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null) { var setup = new SyncSetup(); setup.Tables.Add(table); return(this.DeprovisionAsync(new SyncSet(setup), provision, cancellationToken, progress)); }
public DatabaseProvisionedArgs(SyncContext context, SyncProvision provision, DmSet schema, string script, DbConnection connection, DbTransaction transaction) : base(context, connection, transaction) { Provision = provision; Script = script; Schema = schema; }
/// <summary> /// Provision the remote database /// </summary> /// <param name="overwrite">Overwrite existing objects</param> public virtual Task <ServerScopeInfo> ProvisionAsync(string scopeName, SyncProvision provision = default, bool overwrite = false, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null) { if (provision == SyncProvision.None) { provision = SyncProvision.ServerScope | SyncProvision.ServerHistoryScope | SyncProvision.StoredProcedures | SyncProvision.Triggers | SyncProvision.TrackingTable; } return(this.ProvisionAsync(scopeName, null, provision, overwrite, connection, transaction, cancellationToken, progress)); }
/// <summary> /// Apply the config. /// Create the table if needed /// </summary> public async Task CreateAsync(SyncProvision provision, DbConnection connection, DbTransaction transaction = null) { if (TableDescription.Columns.Count <= 0) { throw new MissingsColumnException(TableDescription.TableName); } if (TableDescription.PrimaryKeys.Count <= 0) { throw new MissingPrimaryKeyException(TableDescription.TableName); } var alreadyOpened = connection.State != ConnectionState.Closed; if (!alreadyOpened) { await connection.OpenAsync().ConfigureAwait(false); } System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); stopwatch.Start(); if (provision.HasFlag(SyncProvision.Table)) { await this.CreateTableAsync(connection, transaction).ConfigureAwait(false); } if (provision.HasFlag(SyncProvision.TrackingTable)) { await this.CreateTrackingTableAsync(connection, transaction).ConfigureAwait(false); } if (provision.HasFlag(SyncProvision.Triggers)) { await this.CreateTriggersAsync(connection, transaction).ConfigureAwait(false); } if (provision.HasFlag(SyncProvision.StoredProcedures)) { await this.CreateStoredProceduresAsync(connection, transaction).ConfigureAwait(false); } stopwatch.Stop(); var str = $"{stopwatch.Elapsed.Minutes}:{stopwatch.Elapsed.Seconds}.{stopwatch.Elapsed.Milliseconds}"; System.Diagnostics.Debug.WriteLine(str); if (!alreadyOpened) { connection.Close(); } }
/// <summary> /// Provision the orchestrator database based on the schema argument, and the provision enumeration /// </summary> /// <param name="schema">Schema to be applied to the database managed by the orchestrator, through the provider.</param> /// <param name="provision">Provision enumeration to determine which components to apply</param> /// <returns>Full schema with table and columns properties</returns> public virtual Task <SyncSet> ProvisionAsync(SyncSet schema, SyncProvision provision, bool overwrite = false, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null) => RunInTransactionAsync(SyncStage.Provisioning, async(ctx, connection, transaction) => { // Check incompatibility with the flags if (this is LocalOrchestrator && (provision.HasFlag(SyncProvision.ServerHistoryScope) || provision.HasFlag(SyncProvision.ServerScope))) { throw new InvalidProvisionForLocalOrchestratorException(); } else if (!(this is LocalOrchestrator) && provision.HasFlag(SyncProvision.ClientScope)) { throw new InvalidProvisionForRemoteOrchestratorException(); } schema = await InternalProvisionAsync(ctx, overwrite, schema, provision, connection, transaction, cancellationToken, progress).ConfigureAwait(false); return(schema); }, connection, transaction, cancellationToken);
/// <summary> /// Apply the config. /// Create the table if needed /// </summary> public async Task CreateAsync(SyncProvision provision, DbConnection connection, DbTransaction transaction = null) { if (TableDescription.Columns.Count <= 0) { throw new MissingsColumnException(TableDescription.TableName); } if (TableDescription.PrimaryKeys.Count <= 0) { throw new MissingPrimaryKeyException(TableDescription.TableName); } var alreadyOpened = connection.State != ConnectionState.Closed; if (!alreadyOpened) { await connection.OpenAsync().ConfigureAwait(false); } if (provision.HasFlag(SyncProvision.Table)) { await this.CreateTableAsync(connection, transaction).ConfigureAwait(false); } if (provision.HasFlag(SyncProvision.TrackingTable)) { await this.CreateTrackingTableAsync(connection, transaction).ConfigureAwait(false); } if (provision.HasFlag(SyncProvision.Triggers)) { await this.CreateTriggersAsync(connection, transaction).ConfigureAwait(false); } if (provision.HasFlag(SyncProvision.StoredProcedures)) { await this.CreateStoredProceduresAsync(connection, transaction).ConfigureAwait(false); } if (!alreadyOpened) { connection.Close(); } }
/// <summary> /// Deprovision the orchestrator database based on the schema argument, and the provision enumeration /// </summary> /// <param name="schema">Schema to be deprovisioned from the database managed by the orchestrator, through the provider.</param> /// <param name="provision">Provision enumeration to determine which components to deprovision</param> public virtual Task DeprovisionAsync(SyncSet schema, SyncProvision provision, ScopeInfo clientScopeInfo = null, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null) => RunInTransactionAsync(SyncStage.Deprovisioning, async(ctx, connection, transaction) => { // Get server scope if not supplied if (clientScopeInfo == null) { var scopeBuilder = this.GetScopeBuilder(this.Options.ScopeInfoTableName); var exists = await this.InternalExistsScopeInfoTableAsync(ctx, DbScopeType.Client, scopeBuilder, connection, transaction, cancellationToken, progress).ConfigureAwait(false); if (exists) { clientScopeInfo = await this.InternalGetScopeAsync <ScopeInfo>(ctx, DbScopeType.Client, this.ScopeName, scopeBuilder, connection, transaction, cancellationToken, progress).ConfigureAwait(false); } } var isDeprovisioned = await InternalDeprovisionAsync(ctx, schema, this.Setup, provision, clientScopeInfo, connection, transaction, cancellationToken, progress).ConfigureAwait(false); return(isDeprovisioned); }, connection, transaction, cancellationToken);
/// <summary> /// Deprovision the orchestrator database based on the provision enumeration /// </summary> /// <param name="provision">Provision enumeration to determine which components to deprovision</param> public virtual Task DeprovisionAsync(SyncProvision provision, ScopeInfo clientScopeInfo = null, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null) { // Create a temporary SyncSet for attaching to the schemaTable var tmpSchema = new SyncSet(); // Add this table to schema foreach (var table in this.Setup.Tables) { tmpSchema.Tables.Add(new SyncTable(table.TableName, table.SchemaName)); } tmpSchema.EnsureSchema(); // copy filters from old setup foreach (var filter in this.Setup.Filters) { tmpSchema.Filters.Add(filter); } return(this.DeprovisionAsync(tmpSchema, provision, clientScopeInfo, connection, transaction, cancellationToken, progress)); }
ProvisionAsync(ServerScopeInfo serverScopeInfo, SyncProvision provision = default, bool overwrite = true, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null) { var context = new SyncContext(Guid.NewGuid(), serverScopeInfo.Name); try { await using var runner = await this.GetConnectionAsync(context, SyncMode.Writing, SyncStage.Provisioning, connection, transaction, cancellationToken, progress).ConfigureAwait(false); ClientScopeInfo clientScopeInfo; (context, clientScopeInfo) = await InternalGetClientScopeInfoAsync(context, runner.Connection, runner.Transaction, runner.CancellationToken, runner.Progress).ConfigureAwait(false); (context, clientScopeInfo) = await InternalProvisionClientAsync(serverScopeInfo, clientScopeInfo, context, provision, overwrite, runner.Connection, runner.Transaction, runner.CancellationToken, runner.Progress).ConfigureAwait(false); await runner.CommitAsync().ConfigureAwait(false); return(clientScopeInfo); } catch (Exception ex) { throw GetSyncError(context, ex); } }
/// <summary> /// Deprovision the orchestrator database based on the schema argument, and the provision enumeration /// </summary> /// <param name="schema">Schema to be deprovisioned from the database managed by the orchestrator, through the provider.</param> /// <param name="provision">Provision enumeration to determine which components to deprovision</param> public virtual Task DeprovisionAsync(SyncProvision provision, ServerScopeInfo serverScopeInfo = null, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null) => RunInTransactionAsync(SyncStage.Deprovisioning, async(ctx, connection, transaction) => { // Get server scope if not supplied if (serverScopeInfo == null) { var scopeBuilder = this.GetScopeBuilder(this.Options.ScopeInfoTableName); var exists = await this.InternalExistsScopeInfoTableAsync(ctx, DbScopeType.Server, scopeBuilder, connection, transaction, cancellationToken, progress).ConfigureAwait(false); if (exists) { serverScopeInfo = await this.InternalGetScopeAsync <ServerScopeInfo>(ctx, DbScopeType.Server, this.ScopeName, scopeBuilder, connection, transaction, cancellationToken, progress).ConfigureAwait(false); } } // Create a temporary SyncSet for attaching to the schemaTable var tmpSchema = new SyncSet(); // Add this table to schema foreach (var table in this.Setup.Tables) { tmpSchema.Tables.Add(new SyncTable(table.TableName, table.SchemaName)); } tmpSchema.EnsureSchema(); // copy filters from old setup foreach (var filter in this.Setup.Filters) { tmpSchema.Filters.Add(filter); } var isDeprovisioned = await InternalDeprovisionAsync(ctx, tmpSchema, this.Setup, provision, serverScopeInfo, connection, transaction, cancellationToken, progress).ConfigureAwait(false); return(isDeprovisioned); }, connection, transaction, cancellationToken);
/// <summary> /// Provision the remote database based on the Setup parameter, and the provision enumeration /// </summary> /// <param name="provision">Provision enumeration to determine which components to apply</param> /// <param name="serverScopeInfo">server scope. Will be saved once provision is done</param> /// <returns>Full schema with table and columns properties</returns> public virtual async Task <ServerScopeInfo> ProvisionAsync(string scopeName, SyncSetup setup = null, SyncProvision provision = default, bool overwrite = false, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null) { var context = new SyncContext(Guid.NewGuid(), scopeName); try { // Check incompatibility with the flags if (provision.HasFlag(SyncProvision.ClientScope)) { throw new InvalidProvisionForRemoteOrchestratorException(); } await using var runner = await this.GetConnectionAsync(context, SyncMode.Writing, SyncStage.Provisioning, connection, transaction, cancellationToken, progress).ConfigureAwait(false); ServerScopeInfo serverScopeInfo; (context, serverScopeInfo) = await this.InternalGetServerScopeInfoAsync(context, setup, runner.Connection, runner.Transaction, runner.CancellationToken, runner.Progress).ConfigureAwait(false); // 2) Provision if (provision == SyncProvision.None) { provision = SyncProvision.TrackingTable | SyncProvision.StoredProcedures | SyncProvision.Triggers; } (context, _) = await this.InternalProvisionAsync(serverScopeInfo, context, false, provision, runner.Connection, runner.Transaction, cancellationToken, progress).ConfigureAwait(false); await runner.CommitAsync().ConfigureAwait(false); return(serverScopeInfo); } catch (Exception ex) { throw GetSyncError(context, ex); } }
/// <summary> /// Deprovision the orchestrator database based the provision enumeration /// Default Deprovision objects are StoredProcedures & Triggers /// </summary> public virtual Task <bool> DeprovisionAsync(SyncProvision provision = default, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null) => DeprovisionAsync(SyncOptions.DefaultScopeName, provision, connection, transaction, cancellationToken);
/// <summary> /// Deprovision the orchestrator database based on the schema argument, and the provision enumeration /// </summary> /// <param name="schema">Schema to be deprovisioned from the database managed by the orchestrator, through the provider.</param> /// <param name="provision">Provision enumeration to determine which components to deprovision</param> public virtual async Task DeprovisionAsync(SyncSet schema, SyncProvision provision, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null) { if (!this.StartTime.HasValue) { this.StartTime = DateTime.UtcNow; } // Get context or create a new one var ctx = this.GetContext(); using (var connection = this.Provider.CreateConnection()) { // Encapsulate in a try catch for a better exception handling // Especially when called from web proxy try { this.logger.LogInformation(SyncEventsId.Deprovision, new { connection.Database, Provision = provision }); ctx.SyncStage = SyncStage.Deprovisioning; // If schema does not have any table, just return if (schema == null || schema.Tables == null || !schema.HasTables) { throw new MissingTablesException(); } // Open connection await this.OpenConnectionAsync(connection, cancellationToken).ConfigureAwait(false); // Create a transaction using (var transaction = connection.BeginTransaction()) { await this.InterceptAsync(new TransactionOpenedArgs(ctx, connection, transaction), cancellationToken).ConfigureAwait(false); await this.InterceptAsync(new DatabaseDeprovisioningArgs(ctx, provision, schema, connection, transaction), cancellationToken).ConfigureAwait(false); await this.Provider.DeprovisionAsync(ctx, schema, this.Setup, provision, this.Options.ScopeInfoTableName, this.Options.DisableConstraintsOnApplyChanges, connection, transaction, cancellationToken, progress); await this.InterceptAsync(new TransactionCommitArgs(ctx, connection, transaction), cancellationToken).ConfigureAwait(false); transaction.Commit(); } ctx.SyncStage = SyncStage.Deprovisioned; await this.CloseConnectionAsync(connection, cancellationToken).ConfigureAwait(false); var args = new DatabaseDeprovisionedArgs(ctx, provision, schema, connection); await this.InterceptAsync(args, cancellationToken).ConfigureAwait(false); this.ReportProgress(ctx, progress, args); } catch (Exception ex) { RaiseError(ex); } finally { if (connection != null && connection.State == ConnectionState.Open) { connection.Close(); } } } }
public override Task <ServerScopeInfo> ProvisionAsync(ServerScopeInfo serverScopeInfo, SyncProvision provision = default, bool overwrite = false, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null) => throw new NotImplementedException();
/// <summary> /// Deprovision a database. You have to passe a configuration object, containing at least the dmTables /// </summary> public async Task <SyncContext> DeprovisionAsync(SyncContext context, SyncSet schema, SyncSetup setup, SyncProvision provision, string scopeInfoTableName, bool disableConstraintsOnApplyChanges, DbConnection connection, DbTransaction transaction, CancellationToken cancellationToken, IProgress <ProgressArgs> progress) { if (schema.Tables == null || !schema.HasTables) { throw new MissingTablesException(); } this.Orchestrator.logger.LogDebug(SyncEventsId.Deprovision, new { TablesCount = schema.Tables.Count, ScopeInfoTableName = scopeInfoTableName, DisableConstraintsOnApplyChanges = disableConstraintsOnApplyChanges, }); // get Database builder var builder = this.GetDatabaseBuilder(); builder.UseChangeTracking = this.UseChangeTracking; builder.UseBulkProcedures = this.SupportBulkOperations; // Sorting tables based on dependencies between them var schemaTables = schema.Tables .SortByDependencies(tab => tab.GetRelations() .Select(r => r.GetParentTable())); // Disable check constraints if (disableConstraintsOnApplyChanges) { foreach (var table in schemaTables.Reverse()) { await this.DisableConstraintsAsync(context, table, setup, connection, transaction).ConfigureAwait(false); } } // Creating a local function to mutualize call var deprovisionFuncAsync = new Func <SyncProvision, IEnumerable <SyncTable>, Task>(async(p, tables) => { foreach (var schemaTable in tables) { var tableBuilder = this.GetTableBuilder(schemaTable, setup); // set if the builder supports creating the bulk operations proc stock tableBuilder.UseBulkProcedures = this.SupportBulkOperations; tableBuilder.UseChangeTracking = this.UseChangeTracking; // adding filter this.AddFilters(schemaTable, tableBuilder); this.Orchestrator.logger.LogDebug(SyncEventsId.Deprovision, schemaTable); await tableBuilder.DropAsync(p, connection, transaction).ConfigureAwait(false); // Interceptor await this.Orchestrator.InterceptAsync(new TableDeprovisionedArgs(context, p, schemaTable, connection, transaction), cancellationToken).ConfigureAwait(false); } }); // Checking if we have to deprovision tables bool hasDeprovisionTableFlag = provision.HasFlag(SyncProvision.Table); // Firstly, removing the flag from the provision, because we need to drop everything in correct order, then drop tables in reverse side if (hasDeprovisionTableFlag) { provision ^= SyncProvision.Table; } // Deprovision everything in order, excepting table await deprovisionFuncAsync(provision, schemaTables).ConfigureAwait(false); // then in reverse side, deprovision tables, if Table was part of Provision enumeration. if (hasDeprovisionTableFlag) { await deprovisionFuncAsync(SyncProvision.Table, schemaTables.Reverse()).ConfigureAwait(false); } if (provision.HasFlag(SyncProvision.ClientScope)) { context = await this.DropClientScopeAsync(context, scopeInfoTableName, connection, transaction, cancellationToken, progress).ConfigureAwait(false); } if (provision.HasFlag(SyncProvision.ServerScope)) { context = await this.DropServerScopeAsync(context, scopeInfoTableName, connection, transaction, cancellationToken, progress).ConfigureAwait(false); } if (provision.HasFlag(SyncProvision.ServerHistoryScope)) { context = await this.DropServerHistoryScopeAsync(context, scopeInfoTableName, connection, transaction, cancellationToken, progress).ConfigureAwait(false); } return(context); }
/// <summary> /// Deprovision the orchestrator database based on the orchestrator Setup instance, provided on constructor, and the provision enumeration /// </summary> /// <param name="provision">Provision enumeration to determine which components to deprovision</param> public virtual Task DeprovisionAsync(SyncProvision provision, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null) => this.DeprovisionAsync(new SyncSet(this.Setup), provision, cancellationToken, progress);
/// <summary> /// Provision the orchestrator database based on the schema argument, and the provision enumeration /// </summary> /// <param name="schema">Schema to be applied to the database managed by the orchestrator, through the provider.</param> /// <param name="provision">Provision enumeration to determine which components to apply</param> /// <returns>Full schema with table and columns properties</returns> public virtual async Task <SyncSet> ProvisionAsync(SyncSet schema, SyncProvision provision, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null) { if (!this.StartTime.HasValue) { this.StartTime = DateTime.UtcNow; } // Get context or create a new one var ctx = this.GetContext(); using (var connection = this.Provider.CreateConnection()) { // log this.logger.LogInformation(SyncEventsId.Provision, new { connection.Database, Provision = provision }); try { ctx.SyncStage = SyncStage.Provisioning; // If schema does not have any table, just return if (schema == null || schema.Tables == null || !schema.HasTables) { throw new MissingTablesException(); } if (this is LocalOrchestrator && (provision.HasFlag(SyncProvision.ServerHistoryScope) || provision.HasFlag(SyncProvision.ServerScope))) { throw new InvalidProvisionForLocalOrchestratorException(); } else if (!(this is LocalOrchestrator) && provision.HasFlag(SyncProvision.ClientScope)) { throw new InvalidProvisionForRemoteOrchestratorException(); } // Open connection await this.OpenConnectionAsync(connection, cancellationToken).ConfigureAwait(false); // Create a transaction using (var transaction = connection.BeginTransaction()) { await this.InterceptAsync(new TransactionOpenedArgs(ctx, connection, transaction), cancellationToken).ConfigureAwait(false); // Check if we have tables AND columns // If we don't have any columns it's most probably because user called method with the Setup only // So far we have only tables names, it's enough to get the schema if (schema.HasTables && !schema.HasColumns) { this.logger.LogInformation(SyncEventsId.GetSchema, this.Setup); (ctx, schema) = await this.Provider.GetSchemaAsync(ctx, this.Setup, connection, transaction, cancellationToken, progress).ConfigureAwait(false); } if (!schema.HasTables) { throw new MissingTablesException(); } if (!schema.HasColumns) { throw new MissingColumnsException(); } await this.InterceptAsync(new DatabaseProvisioningArgs(ctx, provision, schema, connection, transaction), cancellationToken).ConfigureAwait(false); await this.Provider.ProvisionAsync(ctx, schema, this.Setup, provision, this.Options.ScopeInfoTableName, connection, transaction, cancellationToken, progress).ConfigureAwait(false); await this.InterceptAsync(new TransactionCommitArgs(ctx, connection, transaction), cancellationToken).ConfigureAwait(false); transaction.Commit(); } ctx.SyncStage = SyncStage.Provisioned; await this.CloseConnectionAsync(connection, cancellationToken).ConfigureAwait(false); var args = new DatabaseProvisionedArgs(ctx, provision, schema, connection); await this.InterceptAsync(args, cancellationToken).ConfigureAwait(false); this.ReportProgress(ctx, progress, args); } catch (Exception ex) { RaiseError(ex); } finally { if (connection != null && connection.State == ConnectionState.Open) { connection.Close(); } } return(schema); } }
/// <summary> /// Deprovision the remote database. Schema tables are retrieved through setup in parameter. /// </summary> public virtual async Task <bool> DeprovisionAsync(string scopeName, SyncSetup setup, SyncProvision provision = default, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null) { var context = new SyncContext(Guid.NewGuid(), scopeName); try { if (provision == default) { provision = SyncProvision.ServerScope | SyncProvision.ServerHistoryScope | SyncProvision.StoredProcedures | SyncProvision.Triggers | SyncProvision.TrackingTable; } await using var runner = await this.GetConnectionAsync(context, SyncMode.Writing, SyncStage.Deprovisioning, connection, transaction, cancellationToken, progress).ConfigureAwait(false); // Creating a fake scope info var serverScopeInfo = this.InternalCreateScopeInfo(scopeName, DbScopeType.Server); serverScopeInfo.Setup = setup; bool isDeprovisioned; (context, isDeprovisioned) = await InternalDeprovisionAsync(serverScopeInfo, context, provision, runner.Connection, runner.Transaction, cancellationToken, progress).ConfigureAwait(false); await runner.CommitAsync().ConfigureAwait(false); return(isDeprovisioned); } catch (Exception ex) { throw GetSyncError(context, ex); } }
public virtual Task <ServerScopeInfo> ProvisionAsync(SyncSetup setup, SyncProvision provision = default, bool overwrite = false, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null) => ProvisionAsync(SyncOptions.DefaultScopeName, setup, provision, overwrite, connection, transaction, cancellationToken, progress);
/// <summary> /// Provision the local database based on the orchestrator setup, and the provision enumeration /// </summary> /// <param name="provision">Provision enumeration to determine which components to apply</param> public virtual Task <SyncSet> ProvisionAsync(SyncProvision provision, bool overwrite = false, ScopeInfo clientScopeInfo = null, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null) => this.ProvisionAsync(new SyncSet(this.Setup), provision, overwrite, clientScopeInfo, connection, transaction, cancellationToken, progress);
InternalProvisionClientAsync(ServerScopeInfo serverScopeInfo, ClientScopeInfo clientScopeInfo, SyncContext context, SyncProvision provision = default, bool overwrite = true, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null) { try { if (serverScopeInfo.Schema == null) { throw new Exception($"No Schema in your server scope info {serverScopeInfo.Name}"); } if (serverScopeInfo.Schema == null) { throw new Exception($"No Setup in your server scope info {serverScopeInfo.Name}"); } await using var runner = await this.GetConnectionAsync(context, SyncMode.Writing, SyncStage.Provisioning, connection, transaction, cancellationToken, progress).ConfigureAwait(false); // Check incompatibility with the flags if (provision.HasFlag(SyncProvision.ServerHistoryScope) || provision.HasFlag(SyncProvision.ServerScope)) { throw new InvalidProvisionForLocalOrchestratorException(); } // 2) Provision if (provision == SyncProvision.None) { provision = SyncProvision.Table | SyncProvision.StoredProcedures | SyncProvision.Triggers | SyncProvision.TrackingTable; } (context, _) = await this.InternalProvisionAsync(serverScopeInfo, context, overwrite, provision, runner.Connection, runner.Transaction, cancellationToken, progress).ConfigureAwait(false); // set client scope setup and schema clientScopeInfo.Setup = serverScopeInfo.Setup; clientScopeInfo.Schema = serverScopeInfo.Schema; // Write scopes locally (context, clientScopeInfo) = await this.InternalSaveClientScopeInfoAsync(clientScopeInfo, context, runner.Connection, runner.Transaction, cancellationToken, progress).ConfigureAwait(false); await runner.CommitAsync().ConfigureAwait(false); return(context, clientScopeInfo); } catch (Exception ex) { throw GetSyncError(context, ex); } }
/// <summary> /// Deprovision a database. You have to passe a configuration object, containing at least the dmTables /// </summary> public async Task DeprovisionAsync(SyncConfiguration configuration, SyncProvision provision) { DbConnection connection = null; try { if (configuration.Schema == null || !configuration.Schema.HasTables) { throw new ArgumentNullException("tables", "You must set the tables you want to provision"); } // Load the configuration await this.ReadSchemaAsync(configuration.Schema); // Open the connection using (connection = this.CreateConnection()) { await connection.OpenAsync(); using (var transaction = connection.BeginTransaction()) { for (int i = configuration.Count - 1; i >= 0; i--) { // Get the table var dmTable = configuration.Schema.Tables[i]; // get the builder var builder = GetDatabaseBuilder(dmTable); // adding filters this.AddFilters(configuration.Filters, dmTable, builder); if (provision.HasFlag(SyncProvision.TrackingTable) || provision.HasFlag(SyncProvision.All)) { builder.DropTrackingTable(connection, transaction); } if (provision.HasFlag(SyncProvision.StoredProcedures) || provision.HasFlag(SyncProvision.All)) { builder.DropProcedures(connection, transaction); } if (provision.HasFlag(SyncProvision.Triggers) || provision.HasFlag(SyncProvision.All)) { builder.DropTriggers(connection, transaction); } // On purpose, the flag SyncProvision.All does not include the SyncProvision.Table, too dangerous... if (provision.HasFlag(SyncProvision.Table)) { builder.DropTable(connection, transaction); } } if (provision.HasFlag(SyncProvision.Scope) || provision.HasFlag(SyncProvision.All)) { var scopeBuilder = GetScopeBuilder().CreateScopeInfoBuilder(configuration.ScopeInfoTableName, connection, transaction); if (!scopeBuilder.NeedToCreateScopeInfoTable()) { scopeBuilder.DropScopeInfoTable(); } } transaction.Commit(); } } } catch (Exception ex) { throw new SyncException(ex, SyncStage.DatabaseApplying, this.ProviderTypeName); } finally { if (connection != null && connection.State != ConnectionState.Closed) { connection.Close(); } } }
public virtual async Task <ServerScopeInfo> ProvisionAsync(ServerScopeInfo serverScopeInfo, SyncProvision provision = default, bool overwrite = false, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null) { var context = new SyncContext(Guid.NewGuid(), serverScopeInfo.Name); try { (_, serverScopeInfo) = await InternalProvisionServerAsync(serverScopeInfo, context, provision, overwrite, connection, transaction, cancellationToken, progress).ConfigureAwait(false); return(serverScopeInfo); } catch (Exception ex) { throw GetSyncError(context, ex); } }