/// <summary> /// Be sure all tables are ready and configured for sync /// the ScopeSet Configuration MUST be filled by the schema form Database /// </summary> public virtual async Task <SyncContext> EnsureDatabaseAsync(SyncContext context, MessageEnsureDatabase message) { DbConnection connection = null; try { // Event progress context.SyncStage = SyncStage.DatabaseApplying; var script = new StringBuilder(); // Open the connection using (connection = this.CreateConnection()) { await connection.OpenAsync(); using (var transaction = connection.BeginTransaction()) { // Interceptor var beforeArgs = new DatabaseProvisioningArgs(context, SyncProvision.All, message.Schema, connection, transaction); await this.InterceptAsync(beforeArgs); if (message.ScopeInfo.LastSync.HasValue && !beforeArgs.OverwriteSchema) { return(context); } // Sorting tables based on dependencies between them var dmTables = message.Schema.Tables .SortByDependencies(tab => tab.ChildRelations .Select(r => r.ChildTable)); foreach (var dmTable in dmTables) { var builder = this.GetDatabaseBuilder(dmTable); // set if the builder supports creating the bulk operations proc stock builder.UseBulkProcedures = this.SupportBulkOperations; // adding filter this.AddFilters(message.Filters, dmTable, builder); context.SyncStage = SyncStage.DatabaseTableApplying; // Launch any interceptor if available await this.InterceptAsync(new TableProvisioningArgs(context, SyncProvision.All, dmTable, connection, transaction)); string currentScript = null; if (beforeArgs.GenerateScript) { currentScript = builder.ScriptTable(connection, transaction); currentScript += builder.ScriptForeignKeys(connection, transaction); script.Append(currentScript); } builder.Create(connection, transaction); builder.CreateForeignKeys(connection, transaction); // Report & Interceptor context.SyncStage = SyncStage.DatabaseTableApplied; var tableProvisionedArgs = new TableProvisionedArgs(context, SyncProvision.All, dmTable, connection, transaction); this.ReportProgress(context, tableProvisionedArgs); await this.InterceptAsync(tableProvisionedArgs); } // Report & Interceptor context.SyncStage = SyncStage.DatabaseApplied; var args = new DatabaseProvisionedArgs(context, SyncProvision.All, message.Schema, script.ToString(), connection, transaction); this.ReportProgress(context, args); await this.InterceptAsync(args); transaction.Commit(); } connection.Close(); return(context); } } catch (Exception ex) { throw new SyncException(ex, SyncStage.DatabaseApplying); } finally { if (connection != null && connection.State != ConnectionState.Closed) { connection.Close(); } } }
/// <summary> /// Be sure all tables are ready and configured for sync /// the ScopeSet Configuration MUST be filled by the schema form Database /// </summary> public virtual async Task <SyncContext> EnsureDatabaseAsync(SyncContext context, SyncSet schema, DbConnection connection, DbTransaction transaction, CancellationToken cancellationToken, IProgress <ProgressArgs> progress = null) { // Event progress context.SyncStage = SyncStage.SchemaApplying; var script = new StringBuilder(); var beforeArgs = new DatabaseProvisioningArgs(context, SyncProvision.All, schema, connection, transaction); await this.InterceptAsync(beforeArgs).ConfigureAwait(false); // get Database builder var builder = this.GetDatabaseBuilder(); builder.UseChangeTracking = this.UseChangeTracking; builder.UseBulkProcedures = this.SupportBulkOperations; // Initialize database if needed builder.EnsureDatabase(connection, transaction); // Sorting tables based on dependencies between them var schemaTables = schema.Tables .SortByDependencies(tab => tab.GetRelations() .Select(r => r.GetParentTable())); foreach (var schemaTable in schemaTables) { var tableBuilder = this.GetTableBuilder(schemaTable); // 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); context.SyncStage = SyncStage.TableSchemaApplying; // Launch any interceptor if available await this.InterceptAsync(new TableProvisioningArgs(context, SyncProvision.All, schemaTable, connection, transaction)).ConfigureAwait(false); tableBuilder.Create(connection, transaction); tableBuilder.CreateForeignKeys(connection, transaction); // Report & Interceptor context.SyncStage = SyncStage.TableSchemaApplied; var tableProvisionedArgs = new TableProvisionedArgs(context, SyncProvision.All, schemaTable, connection, transaction); this.ReportProgress(context, progress, tableProvisionedArgs); await this.InterceptAsync(tableProvisionedArgs).ConfigureAwait(false); } // Report & Interceptor context.SyncStage = SyncStage.SchemaApplied; var args = new DatabaseProvisionedArgs(context, SyncProvision.All, schema, script.ToString(), connection, transaction); this.ReportProgress(context, progress, args); await this.InterceptAsync(args).ConfigureAwait(false); await this.InterceptAsync(new TransactionCommitArgs(context, connection, transaction)).ConfigureAwait(false); return(context); }
/// <summary> /// Deprovision a database /// </summary> public async Task ProvisionAsync(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"); } // Open the connection using (connection = this.CreateConnection()) { await connection.OpenAsync(); using (var transaction = connection.BeginTransaction()) { // Load the configuration await this.ReadSchemaAsync(configuration.Schema, connection, transaction); var beforeArgs = new DatabaseProvisioningArgs(null, provision, configuration.Schema, connection, transaction); // Launch any interceptor if available await this.InterceptAsync(beforeArgs); if (provision.HasFlag(SyncProvision.Scope) || provision.HasFlag(SyncProvision.All)) { var scopeBuilder = this.GetScopeBuilder().CreateScopeInfoBuilder(configuration.ScopeInfoTableName, connection, transaction); if (scopeBuilder.NeedToCreateScopeInfoTable()) { scopeBuilder.CreateScopeInfoTable(); } } // Sorting tables based on dependencies between them var dmTables = configuration.Schema.Tables .SortByDependencies(tab => tab.ChildRelations .Select(r => r.ChildTable)); foreach (var dmTable in dmTables) { // get the builder var builder = this.GetDatabaseBuilder(dmTable); // call any interceptor await this.InterceptAsync(new TableProvisioningArgs(null, provision, dmTable, connection, transaction)); builder.UseBulkProcedures = this.SupportBulkOperations; // adding filters this.AddFilters(configuration.Filters, dmTable, builder); // On purpose, the flag SyncProvision.All does not include the SyncProvision.Table, too dangerous... if (provision.HasFlag(SyncProvision.Table)) { builder.CreateTable(connection, transaction); } if (provision.HasFlag(SyncProvision.TrackingTable) || provision.HasFlag(SyncProvision.All)) { builder.CreateTrackingTable(connection, transaction); } if (provision.HasFlag(SyncProvision.Triggers) || provision.HasFlag(SyncProvision.All)) { builder.CreateTriggers(connection, transaction); } if (provision.HasFlag(SyncProvision.StoredProcedures) || provision.HasFlag(SyncProvision.All)) { builder.CreateStoredProcedures(connection, transaction); } // call any interceptor await this.InterceptAsync(new TableProvisionedArgs(null, provision, dmTable, connection, transaction)); } // call any interceptor await this.InterceptAsync(new DatabaseProvisionedArgs(null, provision, configuration.Schema, null, connection, transaction)); transaction.Commit(); } connection.Close(); } } catch (Exception ex) { throw new SyncException(ex, SyncStage.DatabaseApplying); } finally { if (connection != null && connection.State != ConnectionState.Closed) { connection.Close(); } } }
/// <summary> /// Deprovision a database /// </summary> public async Task ProvisionAsync(SyncSet schema, SyncProvision provision, string scopeInfoTableName = SyncOptions.DefaultScopeInfoTableName) { DbConnection connection = null; DbTransaction transaction = null; try { if (schema.Tables == null || !schema.HasTables) { throw new MissingTablesException(); } // Open the connection using (connection = this.CreateConnection()) { await connection.OpenAsync().ConfigureAwait(false); // Let provider knows a connection is opened this.OnConnectionOpened(connection); await this.InterceptAsync(new ConnectionOpenArgs(null, connection)).ConfigureAwait(false); using (transaction = connection.BeginTransaction()) { await this.InterceptAsync(new TransactionOpenArgs(null, connection, transaction)).ConfigureAwait(false); var beforeArgs = new DatabaseProvisioningArgs(null, provision, schema, connection, transaction); // Launch any interceptor if available await this.InterceptAsync(beforeArgs).ConfigureAwait(false); // get Database builder var builder = this.GetDatabaseBuilder(); builder.UseChangeTracking = this.UseChangeTracking; builder.UseBulkProcedures = this.SupportBulkOperations; // Initialize database if needed builder.EnsureDatabase(connection, transaction); if (provision.HasFlag(SyncProvision.Scope) || provision.HasFlag(SyncProvision.All)) { var scopeBuilder = this.GetScopeBuilder().CreateScopeInfoBuilder(scopeInfoTableName, connection, transaction); if (scopeBuilder.NeedToCreateScopeInfoTable()) { scopeBuilder.CreateScopeInfoTable(); } } // Sorting tables based on dependencies between them var schemaTables = schema.Tables .SortByDependencies(tab => tab.GetRelations() .Select(r => r.GetParentTable())); foreach (var schemaTable in schemaTables) { // get the builder var tableBuilder = this.GetTableBuilder(schemaTable); // call any interceptor await this.InterceptAsync(new TableProvisioningArgs(null, provision, schemaTable, connection, transaction)).ConfigureAwait(false); tableBuilder.UseBulkProcedures = this.SupportBulkOperations; tableBuilder.UseChangeTracking = this.UseChangeTracking; // adding filters this.AddFilters(schemaTable, tableBuilder); // On purpose, the flag SyncProvision.All does not include the SyncProvision.Table, too dangerous... if (provision.HasFlag(SyncProvision.Table)) { tableBuilder.CreateTable(connection, transaction); } if (provision.HasFlag(SyncProvision.TrackingTable) || provision.HasFlag(SyncProvision.All)) { tableBuilder.CreateTrackingTable(connection, transaction); } if (provision.HasFlag(SyncProvision.Triggers) || provision.HasFlag(SyncProvision.All)) { tableBuilder.CreateTriggers(connection, transaction); } if (provision.HasFlag(SyncProvision.StoredProcedures) || provision.HasFlag(SyncProvision.All)) { tableBuilder.CreateStoredProcedures(connection, transaction); } // call any interceptor await this.InterceptAsync(new TableProvisionedArgs(null, provision, schemaTable, connection, transaction)).ConfigureAwait(false); } // call any interceptor await this.InterceptAsync(new DatabaseProvisionedArgs(null, provision, schema, null, connection, transaction)).ConfigureAwait(false); await this.InterceptAsync(new TransactionCommitArgs(null, connection, transaction)).ConfigureAwait(false); transaction.Commit(); } connection.Close(); } } catch (Exception ex) { throw new SyncException(ex, SyncStage.SchemaApplying); } finally { if (connection != null && connection.State != ConnectionState.Closed) { connection.Close(); } await this.InterceptAsync(new ConnectionCloseArgs(null, connection, transaction)).ConfigureAwait(false); // Let provider knows a connection is closed this.OnConnectionClosed(connection); } }