/// <summary> /// Set common parameters to SelectChanges Sql command /// </summary> internal void SetSelectChangesCommonParameters(SyncContext context, SyncTable syncTable, Guid?excludingScopeId, bool isNew, long?lastTimestamp, DbCommand selectIncrementalChangesCommand) { // Set the parameters DbSyncAdapter.SetParameterValue(selectIncrementalChangesCommand, "sync_min_timestamp", lastTimestamp); DbSyncAdapter.SetParameterValue(selectIncrementalChangesCommand, "sync_scope_id", excludingScopeId.HasValue ? (object)excludingScopeId.Value : DBNull.Value); // Check filters SyncFilter tableFilter = null; // Sqlite does not have any filter, since he can't be server side if (this.Provider.CanBeServerProvider) { tableFilter = syncTable.GetFilter(); } var hasFilters = tableFilter != null; if (!hasFilters) { return; } // context parameters can be null at some point. var contexParameters = context.Parameters ?? new SyncParameters(); foreach (var filterParam in tableFilter.Parameters) { var parameter = contexParameters.FirstOrDefault(p => p.Name.Equals(filterParam.Name, SyncGlobalization.DataSourceStringComparison)); object val = parameter?.Value; DbSyncAdapter.SetParameterValue(selectIncrementalChangesCommand, filterParam.Name, val); } }
/// <summary> /// Set common parameters to SelectChanges Sql command /// </summary> private void SetSelectChangesCommonParameters(SyncContext context, SyncTable syncTable, Guid?excludingScopeId, bool isNew, long lastTimestamp, DbCommand selectIncrementalChangesCommand) { // Generate the isNewScope Flag. var isNewScope = isNew ? 1 : 0; var isReinit = context.SyncType == SyncType.Reinitialize ? 1 : 0; switch (context.SyncWay) { case SyncWay.Upload: // Overwrite if we are in Reinitialize mode (not RenitializeWithUpload) isNewScope = context.SyncType == SyncType.Reinitialize ? 1 : isNewScope; lastTimestamp = context.SyncType == SyncType.Reinitialize ? 0 : lastTimestamp; isReinit = context.SyncType == SyncType.Reinitialize ? 1 : 0; break; case SyncWay.Download: // Ovewrite on bot Reinitialize and ReinitializeWithUpload isNewScope = context.SyncType != SyncType.Normal ? 1 : isNewScope; lastTimestamp = context.SyncType != SyncType.Normal ? 0 : lastTimestamp; isReinit = context.SyncType != SyncType.Normal ? 1 : 0; break; default: break; } // Set the parameters DbTableManagerFactory.SetParameterValue(selectIncrementalChangesCommand, "sync_min_timestamp", lastTimestamp); DbTableManagerFactory.SetParameterValue(selectIncrementalChangesCommand, "sync_scope_id", excludingScopeId.HasValue ? (object)excludingScopeId.Value : DBNull.Value); // Check filters SyncFilter tableFilter = null; // Sqlite does not have any filter, since he can't be server side if (this.CanBeServerProvider) { tableFilter = syncTable.GetFilter(); } var hasFilters = tableFilter != null; if (!hasFilters) { return; } // context parameters can be null at some point. var contexParameters = context.Parameters ?? new SyncParameters(); foreach (var filterParam in tableFilter.Parameters) { var parameter = contexParameters.FirstOrDefault(p => p.Name.Equals(filterParam.Name, SyncGlobalization.DataSourceStringComparison)); object val = parameter?.Value; DbTableManagerFactory.SetParameterValue(selectIncrementalChangesCommand, filterParam.Name, val); } }
/// <summary> /// Get the correct Select changes command /// Can be either /// - SelectInitializedChanges : All changes for first sync /// - SelectChanges : All changes filtered by timestamp /// - SelectInitializedChangesWithFilters : All changes for first sync with filters /// - SelectChangesWithFilters : All changes filtered by timestamp with filters /// </summary> private async Task <DbCommand> GetSelectChangesCommandAsync(SyncContext context, DbSyncAdapter syncAdapter, SyncTable syncTable, bool isNew) { DbCommand selectIncrementalChangesCommand; DbCommandType dbCommandType; SyncFilter tableFilter = null; // Check if we have parameters specified // Sqlite does not have any filter, since he can't be server side if (this.CanBeServerProvider) { tableFilter = syncTable.GetFilter(); } var hasFilters = tableFilter != null; // Determing the correct DbCommandType if (isNew && hasFilters) { dbCommandType = DbCommandType.SelectInitializedChangesWithFilters; } else if (isNew && !hasFilters) { dbCommandType = DbCommandType.SelectInitializedChanges; } else if (!isNew && hasFilters) { dbCommandType = DbCommandType.SelectChangesWithFilters; } else { dbCommandType = DbCommandType.SelectChanges; } // Get correct Select incremental changes command selectIncrementalChangesCommand = syncAdapter.GetCommand(dbCommandType, tableFilter); if (selectIncrementalChangesCommand == null) { throw new MissingCommandException(dbCommandType.ToString()); } // Add common parameters await syncAdapter.SetCommandParametersAsync(dbCommandType, selectIncrementalChangesCommand, tableFilter); return(selectIncrementalChangesCommand); }
/// <summary> /// Validates, that all column filters do refer to a an existing column of the target table /// </summary> /// <param name="filters"></param> /// <param name="tableDescription"></param> public static void ValidateColumnFilters(this SyncFilter filter, SyncTable tableDescription) { if (filter == null) { return; } // TODO : Validate column filters //foreach (var c in filters) //{ // if (c.IsVirtual) // continue; // var columnFilter = tableDescription.Columns[c.ColumnName]; // if (columnFilter == null) // throw new InvalidExpressionException($"Column {c.ColumnName} does not exist in Table {tableDescription.TableName}"); //} }
/// <summary> /// Get the correct Select changes command /// Can be either /// - SelectInitializedChanges : All changes for first sync /// - SelectChanges : All changes filtered by timestamp /// - SelectInitializedChangesWithFilters : All changes for first sync with filters /// - SelectChangesWithFilters : All changes filtered by timestamp with filters /// </summary> internal async Task <DbCommand> GetSelectChangesCommandAsync(SyncContext context, SyncTable syncTable, SyncSetup setup, bool isNew, DbConnection connection, DbTransaction transaction) { DbCommand command; DbCommandType dbCommandType; SyncFilter tableFilter = null; var syncAdapter = this.GetSyncAdapter(syncTable, setup); // Check if we have parameters specified // Sqlite does not have any filter, since he can't be server side if (this.Provider.CanBeServerProvider) { tableFilter = syncTable.GetFilter(); } var hasFilters = tableFilter != null; // Determing the correct DbCommandType if (isNew && hasFilters) { dbCommandType = DbCommandType.SelectInitializedChangesWithFilters; } else if (isNew && !hasFilters) { dbCommandType = DbCommandType.SelectInitializedChanges; } else if (!isNew && hasFilters) { dbCommandType = DbCommandType.SelectChangesWithFilters; } else { dbCommandType = DbCommandType.SelectChanges; } // Get correct Select incremental changes command command = await syncAdapter.GetCommandAsync(dbCommandType, connection, transaction, tableFilter); return(command); }
/// <summary> /// Set parameters on a command /// </summary> public abstract Task SetCommandParametersAsync(DbCommandType commandType, DbCommand command, SyncFilter filter = null);
/// <summary> /// Gets a command from the current adapter /// </summary> public abstract DbCommand GetCommand(DbCommandType commandType, SyncFilter filter = null);
/// <summary> /// Add parameters to a command /// </summary> public abstract Task AddCommandParametersAsync(DbCommandType commandType, DbCommand command, DbConnection connection, DbTransaction transaction, SyncFilter filter = null);
/// <summary> /// Gets a command from the current adapter /// </summary> public abstract (DbCommand Command, bool IsBatchCommand) GetCommand(DbCommandType commandType, SyncFilter filter = null);
/// <summary> /// Get the command from provider, check connection is opened, affect connection and transaction /// Prepare the command parameters and add scope parameters /// </summary> public async Task <(DbCommand Command, bool IsBatch)> GetCommandAsync(DbCommandType commandType, DbConnection connection, DbTransaction transaction, SyncFilter filter = null) { // Create the key var commandKey = $"{connection.DataSource}-{connection.Database}-{this.TableDescription.GetFullName()}-{commandType}"; var(command, isBatch) = GetCommand(commandType, filter); if (command == null) { return(null, false); } // Add Parameters await this.AddCommandParametersAsync(commandType, command, connection, transaction, filter).ConfigureAwait(false); if (command == null) { throw new MissingCommandException(commandType.ToString()); } if (connection == null) { throw new MissingConnectionException(); } if (connection.State != ConnectionState.Open) { throw new ConnectionClosedException(connection); } command.Connection = connection; command.Transaction = transaction; // Get a lazy command instance var lazyCommand = commands.GetOrAdd(commandKey, k => new Lazy <SyncCommand>(() => { var syncCommand = new SyncCommand(commandKey); return(syncCommand); })); // lazyCommand.Metadata is a boolean indicating if the command is already prepared on the server if (lazyCommand.Value.IsPrepared == true) { return(command, isBatch); } // Testing The Prepare() performance increase command.Prepare(); // Adding this command as prepared lazyCommand.Value.IsPrepared = true; commands.AddOrUpdate(commandKey, lazyCommand, (key, lc) => new Lazy <SyncCommand>(() => lc.Value)); return(command, isBatch); }
/// <summary> /// Get the command from provider, check connection is opened, affect connection and transaction /// Prepare the command parameters and add scope parameters /// </summary> internal async Task <DbCommand> PrepareCommandAsync(DbCommandType commandType, DbConnection connection, DbTransaction transaction, SyncFilter filter = null) { // Create the key var commandKey = $"{connection.DataSource}-{connection.Database}-{this.TableDescription.GetFullName()}-{commandType}"; // Get a lazy command instance var lazyCommand = commands.GetOrAdd(commandKey, k => new Lazy <DbCommand>(() => GetCommand(commandType, filter))); // Get the concrete instance var command = lazyCommand.Value; if (command == null) { throw new MissingCommandException(commandType.ToString()); } if (connection == null) { throw new MissingConnectionException(); } if (connection.State != ConnectionState.Open) { throw new ConnectionClosedException(connection); } command.Connection = connection; if (transaction != null) { command.Transaction = transaction; } // Add Parameters await this.AddCommandParametersAsync(commandType, command, connection, transaction, filter).ConfigureAwait(false); // Testing The Prepare() performance increase command.Prepare(); return(command); }
/// <summary> /// Set parameters on a command /// </summary> public abstract void SetCommandParameters(DbCommandType commandType, DbCommand command, SyncFilter filter = null);