Пример #1
0
        GetSnapshotAsync(SyncSet schema = null, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null)
        {
            // Get context or create a new one
            var ctx = this.GetContext();

            BatchInfo serverBatchInfo = null;

            try
            {
                if (string.IsNullOrEmpty(this.Options.SnapshotsDirectory))
                {
                    return(0, null);
                }

                //Direction set to Download
                ctx.SyncWay = SyncWay.Download;

                if (cancellationToken.IsCancellationRequested)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                }

                // Get Schema from remote provider if no schema passed from args
                if (schema == null)
                {
                    var serverScopeInfo = await this.EnsureSchemaAsync(default, default, cancellationToken, progress).ConfigureAwait(false);
Пример #2
0
        /// <summary>
        /// Check if a Stored Procedure exists
        /// </summary>
        /// <param name="table">A table from your Setup instance, where you want to check if the Stored Procedure exists</param>
        /// <param name="storedProcedureType">StoredProcedure type</param>
        public Task <bool> ExistStoredProcedureAsync(SetupTable table, DbStoredProcedureType storedProcedureType, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null)
        => RunInTransactionAsync(SyncStage.None, async(ctx, connection, transaction) =>
        {
            // using a fake SyncTable based on SetupTable, since we don't need columns
            var schemaTable = new SyncTable(table.TableName, table.SchemaName);

            // Create a temporary SyncSet for attaching to the schemaTable
            var schema = new SyncSet();

            // Add this table to schema
            schema.Tables.Add(schemaTable);

            schema.EnsureSchema();

            // copy filters from setup
            foreach (var filter in this.Setup.Filters)
            {
                schema.Filters.Add(filter);
            }

            var tableBuilder = this.GetTableBuilder(schemaTable, this.Setup);

            var exists = await InternalExistsStoredProcedureAsync(ctx, tableBuilder, storedProcedureType, connection, transaction, cancellationToken, progress).ConfigureAwait(false);

            return(exists);
        }, connection, transaction, cancellationToken);
        public ProvisioningArgs(SyncContext context, SyncProvision provision, SyncSet schema, DbConnection connection, DbTransaction transaction)
            : base(context, connection, transaction)

        {
            Provision = provision;
            Schema    = schema;
        }
Пример #4
0
        public DatabaseProvisionedArgs(SyncContext context, SyncProvision provision, SyncSet schema, DbConnection connection = null, DbTransaction transaction = null)
            : base(context, connection, transaction)

        {
            Provision = provision;
            Schema    = schema;
        }
Пример #5
0
        /// <summary>
        /// Read the schema stored from the orchestrator database, through the provider.
        /// </summary>
        /// <returns>Schema containing tables, columns, relations, primary keys</returns>
        public virtual Task <SyncTable> GetTableSchemaAsync(SetupTable table, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null)
        => RunInTransactionAsync(SyncStage.SchemaReading, async(ctx, connection, transaction) =>
        {
            var(schemaTable, _) = await this.InternalGetTableSchemaAsync(ctx, this.Setup, table, connection, transaction, cancellationToken, progress).ConfigureAwait(false);

            if (schemaTable == null)
            {
                throw new MissingTableException(table.GetFullName());
            }

            // Create a temporary SyncSet for attaching to the schemaTable
            var schema = new SyncSet();

            // Add this table to schema
            schema.Tables.Add(schemaTable);

            schema.EnsureSchema();

            // copy filters from setup
            foreach (var filter in this.Setup.Filters)
            {
                schema.Filters.Add(filter);
            }

            return(schemaTable);
        }, connection, transaction, cancellationToken);
Пример #6
0
        /// <summary>
        /// Create a change table with scope columns and tombstone column
        /// </summary>
        public static SyncTable CreateChangesTable(SyncTable syncTable, SyncSet owner)
        {
            if (syncTable.Schema == null)
            {
                throw new ArgumentException("Schema can't be null when creating a changes table");
            }

            // Create an empty sync table without columns
            var changesTable = new SyncTable(syncTable.TableName, syncTable.SchemaName)
            {
                OriginalProvider = syncTable.OriginalProvider,
                SyncDirection    = syncTable.SyncDirection
            };

            // Adding primary keys
            foreach (var pkey in syncTable.PrimaryKeys)
            {
                changesTable.PrimaryKeys.Add(pkey);
            }

            // get ordered columns that are mutables and pkeys
            var orderedNames = syncTable.GetMutableColumnsWithPrimaryKeys();

            foreach (var c in orderedNames)
            {
                changesTable.Columns.Add(c.Clone());
            }

            owner.Tables.Add(changesTable);

            return(changesTable);
        }
Пример #7
0
 public MigratingArgs(SyncContext context, SyncSet newSchema, SyncSetup oldSetup, SyncSetup newSetup, MigrationResults migrationResults, DbConnection connection, DbTransaction transaction) : base(context, connection, transaction)
 {
     this.NewSchema        = newSchema;
     this.OldSetup         = oldSetup;
     this.NewSetup         = newSetup;
     this.MigrationResults = migrationResults;
 }
Пример #8
0
 public SnapshotCreatingArgs(SyncContext context, SyncSet schema, string snapshotDirectory, int batchSize, long timestamp, DbConnection connection, DbTransaction transaction) : base(context, connection, transaction)
 {
     this.Schema            = schema;
     this.SnapshotDirectory = snapshotDirectory;
     this.BatchSize         = batchSize;
     this.Timestamp         = timestamp;
 }
Пример #9
0
        public bool EqualsByProperties(SyncSet otherSet)
        {
            if (otherSet == null)
            {
                return(false);
            }

            // Checking inner lists
            if (!this.Tables.CompareWith(otherSet.Tables))
            {
                return(false);
            }

            if (!this.Filters.CompareWith(otherSet.Filters))
            {
                return(false);
            }

            if (!this.Relations.CompareWith(otherSet.Relations))
            {
                return(false);
            }

            return(true);
        }
Пример #10
0
        /// <summary>
        /// Clone the SyncSet schema (without data)
        /// </summary>
        public SyncSet Clone(bool includeTables = true)
        {
            var clone = new SyncSet();

            if (!includeTables)
            {
                return(clone);
            }

            foreach (var f in this.Filters)
            {
                clone.Filters.Add(f.Clone());
            }

            foreach (var r in this.Relations)
            {
                clone.Relations.Add(r.Clone());
            }

            foreach (var t in this.Tables)
            {
                clone.Tables.Add(t.Clone());
            }

            // Ensure all elements has the correct ref to its parent
            clone.EnsureSchema();

            return(clone);
        }
Пример #11
0
        /// <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);
        /// <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));
        }
        internal virtual async Task <bool> InternalUpgradeAsync(SyncContext context, SyncSet schema, ScopeInfo scopeInfo, DbScopeBuilder builder, DbConnection connection, DbTransaction transaction,
                                                                CancellationToken cancellationToken, IProgress <ProgressArgs> progress)
        {
            var version    = SyncVersion.EnsureVersion(scopeInfo.Version);
            var oldVersion = version.Clone() as Version;

            // beta version
            if (version.Major == 0)
            {
                // Migrate from 0.5.x to 0.6.0
                if (version.Minor <= 5)
                {
                    version = await UpgdrateTo600Async(context, schema, connection, transaction, cancellationToken, progress).ConfigureAwait(false);
                }

                // Migrate from 0.6.0 to 0.6.1
                if (version.Minor <= 6 && version.Build <= 0)
                {
                    version = await UpgdrateTo601Async(context, schema, connection, transaction, cancellationToken, progress).ConfigureAwait(false);
                }
            }

            if (oldVersion != version)
            {
                scopeInfo.Version = version.ToString();
                await this.InternalSaveScopeAsync(context, DbScopeType.Client, scopeInfo, builder, connection, transaction, cancellationToken, progress).ConfigureAwait(false);
            }
            return(version == SyncVersion.Current);
        }
Пример #14
0
 public SyncRelation(string relationName, IList <SyncColumnIdentifier> columns, IList <SyncColumnIdentifier> parentColumns, SyncSet schema = null)
 {
     this.RelationName = relationName;
     this.ParentKeys   = parentColumns;
     this.Keys         = columns;
     this.Schema       = schema;
 }
Пример #15
0
        /// <summary>
        /// Drop all Stored Procedures
        /// </summary>
        /// <param name="table">A table from your Setup instance, where you want to drop all the Stored Procedures</param>
        public Task <bool> DropStoredProceduresAsync(SetupTable table, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null)
        => RunInTransactionAsync(SyncStage.Deprovisioning, async(ctx, connection, transaction) =>
        {
            var hasDroppedAtLeastOneStoredProcedure = false;

            // using a fake SyncTable based on SetupTable, since we don't need columns
            var schemaTable = new SyncTable(table.TableName, table.SchemaName);

            // Create a temporary SyncSet for attaching to the schemaTable
            var schema = new SyncSet();

            // Add this table to schema
            schema.Tables.Add(schemaTable);

            schema.EnsureSchema();

            // copy filters from setup
            foreach (var filter in this.Setup.Filters)
            {
                schema.Filters.Add(filter);
            }

            // using a fake SyncTable based on SetupTable, since we don't need columns
            var tableBuilder = this.GetTableBuilder(schemaTable, this.Setup);

            // check bulk before
            hasDroppedAtLeastOneStoredProcedure = await InternalDropStoredProceduresAsync(ctx, tableBuilder, connection, transaction, cancellationToken, progress).ConfigureAwait(false);

            // Removing cached commands
            var syncAdapter = this.GetSyncAdapter(schemaTable, this.Setup);
            syncAdapter.RemoveCommands();

            return(hasDroppedAtLeastOneStoredProcedure);
        }, connection, transaction, cancellationToken);
        /// <summary>
        /// Create all tables
        /// </summary>
        /// <param name="schema">A complete schema you want to create, containing table, primary keys and relations</param>
        public Task <bool> CreateTablesAsync(SyncSet schema, bool overwrite = false, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null)
        => RunInTransactionAsync(SyncStage.Provisioning, async(ctx, connection, transaction) =>
        {
            var atLeastOneHasBeenCreated = false;

            // Sorting tables based on dependencies between them
            var schemaTables = schema.Tables.SortByDependencies(tab => tab.GetRelations().Select(r => r.GetParentTable()));

            // if we overwritten all tables, we need to delete all of them, before recreating them
            if (overwrite)
            {
                foreach (var schemaTable in schemaTables.Reverse())
                {
                    var tableBuilder = this.GetTableBuilder(schemaTable, this.Setup);
                    var exists       = await InternalExistsTableAsync(ctx, tableBuilder, connection, transaction, cancellationToken, progress).ConfigureAwait(false);

                    if (exists)
                    {
                        await InternalDropTableAsync(ctx, tableBuilder, connection, transaction, cancellationToken, progress).ConfigureAwait(false);
                    }
                }
            }
            // Then create them
            foreach (var schemaTable in schema.Tables)
            {
                // Get table builder
                var tableBuilder = this.GetTableBuilder(schemaTable, this.Setup);

                var schemaExists = await InternalExistsSchemaAsync(ctx, tableBuilder, connection, transaction, cancellationToken, progress).ConfigureAwait(false);

                if (!schemaExists)
                {
                    await InternalCreateSchemaAsync(ctx, tableBuilder, connection, transaction, cancellationToken, progress).ConfigureAwait(false);
                }

                var exists = await InternalExistsTableAsync(ctx, tableBuilder, connection, transaction, cancellationToken, progress).ConfigureAwait(false);

                // should create only if not exists OR if overwrite has been set
                var shouldCreate = !exists || overwrite;

                if (shouldCreate)
                {
                    // Drop if already exists and we need to overwrite
                    if (exists && overwrite)
                    {
                        await InternalDropTableAsync(ctx, tableBuilder, connection, transaction, cancellationToken, progress).ConfigureAwait(false);
                    }

                    var hasBeenCreated = await InternalCreateTableAsync(ctx, tableBuilder, connection, transaction, cancellationToken, progress).ConfigureAwait(false);

                    if (hasBeenCreated)
                    {
                        atLeastOneHasBeenCreated = true;
                    }
                }
            }

            return(atLeastOneHasBeenCreated);
        }, connection, transaction, cancellationToken);
Пример #17
0
        public DatabaseProvisionedArgs(SyncContext context, SyncProvision provision, SyncSet schema, string script, DbConnection connection, DbTransaction transaction)
            : base(context, connection, transaction)

        {
            Provision = provision;
            Script    = script;
            Schema    = schema;
        }
Пример #18
0
        /// <summary>
        /// Ensure filter has the correct schema (since the property is not serialized
        /// </summary>
        public void EnsureFilter(SyncSet schema)
        {
            this.Schema = schema;

            this.Parameters.EnsureFilters(this.Schema);
            this.Wheres.EnsureFilters(this.Schema);
            this.Joins.EnsureFilters(this.Schema);
        }
        /// <summary>
        /// Gets a batch of changes to synchronize when given batch size,
        /// destination knowledge, and change data retriever parameters.
        /// </summary>
        /// <returns>A DbSyncContext object that will be used to retrieve the modified data.</returns>
        public virtual (SyncContext, BatchInfo) GetSnapshot(
            SyncContext context, SyncSet schema, string batchDirectory,
            CancellationToken cancellationToken, IProgress <ProgressArgs> progress = null)
        {
            var sb         = new StringBuilder();
            var underscore = "";

            if (context.Parameters != null)
            {
                foreach (var p in context.Parameters.OrderBy(p => p.Name))
                {
                    var cleanValue = new string(p.Value.ToString().Where(char.IsLetterOrDigit).ToArray());
                    var cleanName  = new string(p.Name.Where(char.IsLetterOrDigit).ToArray());

                    sb.Append($"{underscore}{cleanName}_{cleanValue}");
                    underscore = "_";
                }
            }

            var directoryName = sb.ToString();

            directoryName = string.IsNullOrEmpty(directoryName) ? "ALL" : directoryName;

            var directoryFullPath = Path.Combine(batchDirectory, directoryName);

            // if no snapshot present, just return null value.
            if (!Directory.Exists(directoryFullPath))
            {
                return(context, null);
            }

            // Serialize on disk.
            var jsonConverter = new JsonConverter <BatchInfo>();

            var summaryFileName = Path.Combine(directoryFullPath, "summary.json");

            BatchInfo batchInfo = null;

            // Create the schema changeset
            var changesSet = new SyncSet(schema.ScopeName);

            // Create a Schema set without readonly columns, attached to memory changes
            foreach (var table in schema.Tables)
            {
                DbSyncAdapter.CreateChangesTable(schema.Tables[table.TableName, table.SchemaName], changesSet);
            }


            using (var fs = new FileStream(summaryFileName, FileMode.Open, FileAccess.Read))
            {
                batchInfo = jsonConverter.Deserialize(fs);
            }

            batchInfo.SetSchema(changesSet);

            return(context, batchInfo);
        }
Пример #20
0
        /// <summary>
        /// Update all untracked rows from the client database
        /// </summary>
        public virtual async Task UpdateUntrackedRowsAsync(SyncSet schema, 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())
            {
                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();
                    }

                    // 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);

                        // Update untracked rows
                        await this.Provider.UpdateUntrackedRowsAsync(ctx, schema, this.Setup, connection, transaction, cancellationToken, progress);

                        await this.InterceptAsync(new TransactionCommitArgs(ctx, connection, transaction), cancellationToken).ConfigureAwait(false);

                        transaction.Commit();
                    }

                    ctx.SyncStage = SyncStage.Provisioned;

                    await this.CloseConnectionAsync(connection, cancellationToken).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    RaiseError(ex);
                }
                finally
                {
                    if (connection != null && connection.State == ConnectionState.Open)
                    {
                        connection.Close();
                    }
                }
            }
        }
Пример #21
0
        protected virtual void Dispose(bool cleanup)
        {
            // Dispose managed ressources
            if (cleanup)
            {
                // clean rows
                this.Schema = null;
            }

            // Dispose unmanaged ressources
        }
Пример #22
0
        private async Task <Version> UpgdrateTo601Async(SyncContext context, SyncSet schema, DbConnection connection, DbTransaction transaction,
                                                        CancellationToken cancellationToken, IProgress <ProgressArgs> progress)
        {
            var newVersion = new Version(0, 6, 1);
            // Sorting tables based on dependencies between them
            var schemaTables = schema.Tables
                               .SortByDependencies(tab => tab.GetRelations()
                                                   .Select(r => r.GetParentTable()));

            var message = $"Upgrade to {newVersion}:";
            var args    = new UpgradeProgressArgs(context, message, newVersion, connection, transaction);

            this.ReportProgress(context, progress, args, connection, transaction);


            foreach (var schemaTable in schemaTables)
            {
                var tableBuilder = this.GetTableBuilder(schemaTable, this.Setup);


                // Upgrade Select Initial Changes
                var exists = await InternalExistsStoredProcedureAsync(context, tableBuilder, DbStoredProcedureType.SelectInitializedChanges, connection, transaction, cancellationToken, progress).ConfigureAwait(false);

                if (exists)
                {
                    await InternalDropStoredProcedureAsync(context, tableBuilder, DbStoredProcedureType.SelectInitializedChanges, connection, transaction, cancellationToken, progress).ConfigureAwait(false);
                }
                await InternalCreateStoredProcedureAsync(context, tableBuilder, DbStoredProcedureType.SelectInitializedChanges, connection, transaction, cancellationToken, progress).ConfigureAwait(false);

                args = new UpgradeProgressArgs(context, $"SelectInitializedChanges stored procedure for table {tableBuilder.TableDescription.GetFullName()} updated", newVersion, connection, transaction);
                this.ReportProgress(context, progress, args, connection, transaction);

                // Upgrade Select Initial Changes With Filter
                if (tableBuilder.TableDescription.GetFilter() != null)
                {
                    var existsWithFilter = await InternalExistsStoredProcedureAsync(context, tableBuilder, DbStoredProcedureType.SelectInitializedChangesWithFilters, connection, transaction, cancellationToken, progress).ConfigureAwait(false);

                    if (existsWithFilter)
                    {
                        await InternalDropStoredProcedureAsync(context, tableBuilder, DbStoredProcedureType.SelectInitializedChangesWithFilters, connection, transaction, cancellationToken, progress).ConfigureAwait(false);
                    }
                    await InternalCreateStoredProcedureAsync(context, tableBuilder, DbStoredProcedureType.SelectInitializedChangesWithFilters, connection, transaction, cancellationToken, progress).ConfigureAwait(false);

                    args = new UpgradeProgressArgs(context, $"SelectInitializedChangesWithFilters stored procedure for table {tableBuilder.TableDescription.GetFullName()} updated", newVersion, connection, transaction);
                    this.ReportProgress(context, progress, args, connection, transaction);
                }
            }

            message = "Upgrade to 0.6.1 done.";
            args    = new UpgradeProgressArgs(context, message, newVersion, connection, transaction);
            this.ReportProgress(context, progress, args, connection, transaction);

            return(newVersion);
        }
Пример #23
0
        /// <summary>
        /// Provision the local database based on the orchestrator setup, and the provision enumeration
        /// </summary>
        /// <param name="overwrite">Overwrite existing objects</param>
        public virtual Task <SyncSet> ProvisionAsync(SyncSet schema = null, bool overwrite = false, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null)
        {
            var provision = SyncProvision.ClientScope | SyncProvision.Table |
                            SyncProvision.StoredProcedures | SyncProvision.Triggers | SyncProvision.TrackingTable;

            if (schema == null)
            {
                schema = new SyncSet(this.Setup);
            }

            return(this.ProvisionAsync(schema, provision, overwrite, null, connection, transaction, cancellationToken, progress));
        }
Пример #24
0
        private Task <Version> UpgdrateTo703Async(SyncContext context, SyncSet schema, SyncSetup setup, DbConnection connection, DbTransaction transaction, CancellationToken cancellationToken, IProgress <ProgressArgs> progress)
        {
            var newVersion = new Version(0, 7, 3);

            var message = $"Upgrade to {newVersion}:";
            var args    = new UpgradeProgressArgs(context, message, newVersion, connection, transaction);

            this.ReportProgress(context, progress, args, connection, transaction);


            return(Task.FromResult(newVersion));
        }
Пример #25
0
        /// <summary>
        /// Ensure table as the correct schema (since the property is not serialized
        /// </summary>
        public void EnsureTable(SyncSet schema)
        {
            this.Schema = schema;

            if (this.Columns != null)
            {
                this.Columns.EnsureColumns(this);
            }

            if (this.Rows != null)
            {
                this.Rows.EnsureRows(this);
            }
        }
Пример #26
0
        /// <summary>
        /// Disabling all constraints on synced tables
        /// Since we can disable at the database level
        /// Just check for one available table and execute for the whole db
        /// </summary>
        internal void DisableConstraints(SyncContext context, SyncSet schema, DbConnection connection, DbTransaction transaction = null)
        {
            if (schema == null || schema.Tables.Count <= 0)
            {
                return;
            }

            // arbitrary table
            var tableDescription = schema.Tables[0];

            var builder     = this.GetTableBuilder(tableDescription);
            var syncAdapter = builder.CreateSyncAdapter(connection, transaction);

            // disable constraints
            syncAdapter.DisableConstraints();
        }
        /// <summary>
        /// Delete metadatas items from tracking tables
        /// </summary>
        /// <param name="timeStampStart">Timestamp start. Used to limit the delete metadatas rows from now to this timestamp</param>
        /// <param name="cancellationToken">Cancellation token</param>
        /// <param name="progress">Progress args</param>
        public virtual Task <DatabaseMetadatasCleaned> DeleteMetadatasAsync(long?timeStampStart, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null)
        => RunInTransactionAsync(SyncStage.MetadataCleaning, async(ctx, connection, transaction) =>
        {
            if (!timeStampStart.HasValue)
            {
                return(null);
            }

            // Create a dummy schema to be able to call the DeprovisionAsync method on the provider
            // No need columns or primary keys to be able to deprovision a table
            SyncSet schema = new SyncSet(this.Setup);

            var databaseMetadatasCleaned = await this.InternalDeleteMetadatasAsync(ctx, schema, this.Setup, timeStampStart.Value, connection, transaction, cancellationToken, progress).ConfigureAwait(false);

            return(databaseMetadatasCleaned);
        }, connection, transaction, cancellationToken);
Пример #28
0
        /// <summary>
        /// update configuration object with tables desc from server database
        /// </summary>
        internal async Task <SyncSet> InternalGetSchemaAsync(SyncContext context, SyncSetup setup, DbConnection connection, DbTransaction transaction,
                                                             CancellationToken cancellationToken, IProgress <ProgressArgs> progress)
        {
            if (setup == null || setup.Tables.Count <= 0)
            {
                throw new MissingTablesException();
            }

            await this.InterceptAsync(new SchemaLoadingArgs(context, setup, connection, transaction), cancellationToken).ConfigureAwait(false);

            // Create the schema
            var schema = new SyncSet();

            // copy filters from setup
            foreach (var filter in setup.Filters)
            {
                schema.Filters.Add(filter);
            }

            var relations = new List <DbRelationDefinition>(20);

            foreach (var setupTable in setup.Tables)
            {
                var(syncTable, tableRelations) = await InternalGetTableSchemaAsync(context, setup, setupTable, connection, transaction, cancellationToken, progress);

                // Add this table to schema
                schema.Tables.Add(syncTable);

                // Since we are not sure of the order of reading tables
                // create a tmp relations list
                relations.AddRange(tableRelations);
            }

            // Parse and affect relations to schema
            SetRelations(relations, schema);

            // Ensure all objects have correct relations to schema
            schema.EnsureSchema();

            var schemaArgs = new SchemaLoadedArgs(context, schema, connection);

            await this.InterceptAsync(schemaArgs, cancellationToken).ConfigureAwait(false);

            this.ReportProgress(context, progress, schemaArgs);

            return(schema);
        }
Пример #29
0
        /// <summary>
        /// Create a Stored Procedure
        /// </summary>
        /// <param name="table">A table from your Setup instance, where you want to create the Stored Procedure</param>
        /// <param name="storedProcedureType">StoredProcedure type</param>
        /// <param name="overwrite">If true, drop the existing stored procedure then create again</param>
        public Task <bool> CreateStoredProcedureAsync(SetupTable table, DbStoredProcedureType storedProcedureType, bool overwrite = false, DbConnection connection = default, DbTransaction transaction = default, CancellationToken cancellationToken = default, IProgress <ProgressArgs> progress = null)
        => RunInTransactionAsync(SyncStage.Provisioning, async(ctx, connection, transaction) =>
        {
            bool hasBeenCreated = false;

            var(schemaTable, _) = await this.InternalGetTableSchemaAsync(ctx, this.Setup, table, connection, transaction, cancellationToken, progress).ConfigureAwait(false);

            if (schemaTable == null)
            {
                throw new MissingTableException(table.GetFullName());
            }

            // Create a temporary SyncSet for attaching to the schemaTable
            var schema = new SyncSet();

            // Add this table to schema
            schema.Tables.Add(schemaTable);

            schema.EnsureSchema();

            // copy filters from setup
            foreach (var filter in this.Setup.Filters)
            {
                schema.Filters.Add(filter);
            }

            // Get table builder
            var tableBuilder = this.GetTableBuilder(schemaTable, this.Setup);

            var exists = await InternalExistsStoredProcedureAsync(ctx, tableBuilder, storedProcedureType, connection, transaction, cancellationToken, progress).ConfigureAwait(false);

            // should create only if not exists OR if overwrite has been set
            var shouldCreate = !exists || overwrite;

            if (shouldCreate)
            {
                // Drop storedProcedure if already exists
                if (exists && overwrite)
                {
                    await InternalDropStoredProcedureAsync(ctx, tableBuilder, storedProcedureType, connection, transaction, cancellationToken, progress).ConfigureAwait(false);
                }

                hasBeenCreated = await InternalCreateStoredProcedureAsync(ctx, tableBuilder, storedProcedureType, connection, transaction, cancellationToken, progress).ConfigureAwait(false);
            }

            return(hasBeenCreated);
        }, connection, transaction, cancellationToken);
        /// <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);