Exemplo n.º 1
0
        /// <summary>
        /// Apply changes internal method for one Insert or Update or Delete for every dbSyncAdapter
        /// </summary>
        internal ChangeApplicationAction ApplyChangesInternal(SyncContext context, DbConnection connection, DbTransaction transaction, ScopeInfo fromScope, BatchInfo changes, DmRowState applyType, ChangesApplied changesApplied)
        {
            ChangeApplicationAction changeApplicationAction = ChangeApplicationAction.Continue;

            var configuration = GetCacheConfiguration();

            // for each adapters (Zero to End for Insert / Updates -- End to Zero for Deletes
            for (int i = 0; i < configuration.Count; i++)
            {
                // If we have a delete we must go from Up to Down, orthewise Dow to Up index
                var tableDescription = (applyType != DmRowState.Deleted ?
                                        configuration[i] :
                                        configuration[configuration.Count - i - 1]);

                // if we are in upload stage, so check if table is not download only
                if (context.SyncWay == SyncWay.Upload && tableDescription.SyncDirection == SyncDirection.DownloadOnly)
                {
                    continue;
                }

                // if we are in download stage, so check if table is not download only
                if (context.SyncWay == SyncWay.Download && tableDescription.SyncDirection == SyncDirection.UploadOnly)
                {
                    continue;
                }


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

                syncAdapter.ConflictApplyAction = configuration.GetApplyAction();

                // Set syncAdapter properties
                syncAdapter.applyType = applyType;

                // Get conflict handler resolver
                if (syncAdapter.ConflictActionInvoker == null && this.ApplyChangedFailed != null)
                {
                    syncAdapter.ConflictActionInvoker = GetConflictAction;
                }

                if (changes.BatchPartsInfo != null && changes.BatchPartsInfo.Count > 0)
                {
                    // getting the table to be applied
                    // we may have multiple batch files, so we can have multipe dmTable with the same Name
                    // We can say that dmTable may be contained in several files
                    foreach (DmTable dmTablePart in changes.GetTable(tableDescription.TableName))
                    {
                        if (dmTablePart == null || dmTablePart.Rows.Count == 0)
                        {
                            continue;
                        }

                        // check and filter
                        var dmChangesView = new DmView(dmTablePart, (r) => r.RowState == applyType);

                        if (dmChangesView.Count == 0)
                        {
                            dmChangesView.Dispose();
                            dmChangesView = null;
                            continue;
                        }

                        // Conflicts occured when trying to apply rows
                        List <SyncConflict> conflicts = new List <SyncConflict>();

                        // Raise event progress only if there are rows to be applied
                        context.SyncStage = SyncStage.TableChangesApplying;
                        var args = new TableChangesApplyingEventArgs(this.ProviderTypeName, context.SyncStage, tableDescription.TableName, applyType);
                        this.TryRaiseProgressEvent(args, this.TableChangesApplying);

                        int rowsApplied;
                        // applying the bulkchanges command
                        if (configuration.UseBulkOperations && this.SupportBulkOperations)
                        {
                            rowsApplied = syncAdapter.ApplyBulkChanges(dmChangesView, fromScope, conflicts);
                        }
                        else
                        {
                            rowsApplied = syncAdapter.ApplyChanges(dmChangesView, fromScope, conflicts);
                        }

                        // If conflicts occured
                        // Eventuall, conflicts are resolved on server side.
                        if (conflicts != null && conflicts.Count > 0)
                        {
                            foreach (var conflict in conflicts)
                            {
                                var scopeBuilder     = this.GetScopeBuilder();
                                var scopeInfoBuilder = scopeBuilder.CreateScopeInfoBuilder(connection, transaction);
                                var localTimeStamp   = scopeInfoBuilder.GetLocalTimestamp();

                                changeApplicationAction = syncAdapter.HandleConflict(conflict, fromScope, localTimeStamp, out DmRow resolvedRow);

                                if (changeApplicationAction == ChangeApplicationAction.Continue)
                                {
                                    // row resolved
                                    if (resolvedRow != null)
                                    {
                                        rowsApplied++;
                                    }
                                }
                                else
                                {
                                    context.TotalSyncErrors++;
                                    // TODO : Should we break at the first error ?
                                    return(ChangeApplicationAction.Rollback);
                                }
                            }
                        }

                        // Get all conflicts resolved
                        context.TotalSyncConflicts = conflicts.Where(c => c.Type != ConflictType.ErrorsOccurred).Sum(c => 1);

                        // Handle sync progress for this syncadapter (so this table)
                        var changedFailed = dmChangesView.Count - rowsApplied;

                        // raise SyncProgress Event

                        var existAppliedChanges = changesApplied.TableChangesApplied.FirstOrDefault(
                            sc => string.Equals(sc.TableName, tableDescription.TableName) && sc.State == applyType);

                        if (existAppliedChanges == null)
                        {
                            existAppliedChanges = new TableChangesApplied
                            {
                                TableName = tableDescription.TableName,
                                Applied   = rowsApplied,
                                Failed    = changedFailed,
                                State     = applyType
                            };
                            changesApplied.TableChangesApplied.Add(existAppliedChanges);
                        }
                        else
                        {
                            existAppliedChanges.Applied += rowsApplied;
                            existAppliedChanges.Failed  += changedFailed;
                        }

                        // Event progress
                        context.SyncStage = SyncStage.TableChangesApplied;
                        var progressEventArgs = new TableChangesAppliedEventArgs(this.ProviderTypeName, context.SyncStage, existAppliedChanges);
                        this.TryRaiseProgressEvent(progressEventArgs, this.TableChangesApplied);
                    }
                }

                // Dispose conflict handler resolver
                if (syncAdapter.ConflictActionInvoker != null)
                {
                    syncAdapter.ConflictActionInvoker = null;
                }
            }

            return(ChangeApplicationAction.Continue);
        }