/// <summary>
        /// Try to apply changes on the server.
        /// Internally will call ApplyUpdate or ApplyDelete and will return
        /// </summary>
        /// <param name="changes">Changes</param>
        /// <returns>every lines not updated / deleted in the destination data source</returns>
        internal async Task <int> ApplyChangesAsync(Guid localScopeId, Guid senderScopeId, SyncTable changesTable, long lastTimestamp, List <SyncConflict> conflicts)
        {
            int appliedRows = 0;

            foreach (var row in changesTable.Rows)
            {
                bool operationComplete = false;

                try
                {
                    if (ApplyType == DataRowState.Modified)
                    {
                        operationComplete = await this.ApplyUpdateAsync(row, lastTimestamp, senderScopeId, false).ConfigureAwait(false);
                    }
                    else if (ApplyType == DataRowState.Deleted)
                    {
                        operationComplete = await this.ApplyDeleteAsync(row, lastTimestamp, senderScopeId, false).ConfigureAwait(false);
                    }

                    if (operationComplete)
                    {
                        appliedRows++;
                    }
                    else
                    {
                        conflicts.Add(GetConflict(row, await GetRowAsync(localScopeId, row, changesTable).ConfigureAwait(false)));
                    }
                }
                catch (Exception ex)
                {
                    if (this.IsUniqueKeyViolation(ex))
                    {
                        // Generate the conflict
                        var conflict = new SyncConflict(ConflictType.UniqueKeyConstraint);

                        // Add the row as Remote row
                        conflict.AddRemoteRow(row);

                        // Get the local row
                        var localRow = await GetRowAsync(localScopeId, row, changesTable).ConfigureAwait(false);

                        if (localRow != null)
                        {
                            conflict.AddLocalRow(localRow);
                        }

                        conflicts.Add(conflict);
                    }
                    else
                    {
                        throw;
                    }
                }
            }

            return(appliedRows);
        }
        /// <summary>
        /// We have a conflict, try to get the source row and generate a conflict
        /// </summary>
        private SyncConflict GetConflict(SyncRow remoteConflictRow, SyncRow localConflictRow)
        {
            var dbConflictType = ConflictType.ErrorsOccurred;

            if (remoteConflictRow == null)
            {
                throw new UnknownException("THAT can't happen...");
            }


            // local row is null
            if (localConflictRow == null && remoteConflictRow.RowState == DataRowState.Modified)
            {
                dbConflictType = ConflictType.RemoteExistsLocalNotExists;
            }
            else if (localConflictRow == null && remoteConflictRow.RowState == DataRowState.Deleted)
            {
                dbConflictType = ConflictType.RemoteIsDeletedLocalNotExists;
            }

            //// remote row is null. Can't happen
            //else if (remoteConflictRow == null && localConflictRow.RowState == DataRowState.Modified)
            //    dbConflictType = ConflictType.RemoteNotExistsLocalExists;
            //else if (remoteConflictRow == null && localConflictRow.RowState == DataRowState.Deleted)
            //    dbConflictType = ConflictType.RemoteNotExistsLocalIsDeleted;

            else if (remoteConflictRow.RowState == DataRowState.Deleted && localConflictRow.RowState == DataRowState.Deleted)
            {
                dbConflictType = ConflictType.RemoteIsDeletedLocalIsDeleted;
            }
            else if (remoteConflictRow.RowState == DataRowState.Modified && localConflictRow.RowState == DataRowState.Deleted)
            {
                dbConflictType = ConflictType.RemoteExistsLocalIsDeleted;
            }
            else if (remoteConflictRow.RowState == DataRowState.Deleted && localConflictRow.RowState == DataRowState.Modified)
            {
                dbConflictType = ConflictType.RemoteIsDeletedLocalExists;
            }
            else if (remoteConflictRow.RowState == DataRowState.Modified && localConflictRow.RowState == DataRowState.Modified)
            {
                dbConflictType = ConflictType.RemoteExistsLocalExists;
            }

            // Generate the conflict
            var conflict = new SyncConflict(dbConflictType);

            conflict.AddRemoteRow(remoteConflictRow);

            if (localConflictRow != null)
            {
                conflict.AddLocalRow(localConflictRow);
            }

            return(conflict);
        }
        /// <summary>
        /// We have a conflict, try to get the source row and generate a conflict
        /// </summary>
        private SyncConflict GetConflict(SyncRow remoteConflictRow, SyncRow localConflictRow)
        {
            var dbConflictType = ConflictType.ErrorsOccurred;

            // Can't find the row on the server datastore
            if (localConflictRow == null)
            {
                if (ApplyType == DataRowState.Modified)
                {
                    dbConflictType = ConflictType.RemoteExistsLocalNotExists;
                }
                else if (ApplyType == DataRowState.Deleted)
                {
                    dbConflictType = ConflictType.RemoteIsDeletedLocalNotExists;
                }
            }
            else
            {
                // the row on local is deleted
                if (localConflictRow.RowState == DataRowState.Deleted)
                {
                    if (ApplyType == DataRowState.Modified)
                    {
                        dbConflictType = ConflictType.RemoteExistsLocalIsDeleted;
                    }
                    else if (ApplyType == DataRowState.Deleted)
                    {
                        dbConflictType = ConflictType.RemoteIsDeletedLocalIsDeleted;
                    }
                }
                else
                {
                    dbConflictType = ConflictType.RemoteExistsLocalExists;
                }
            }
            // Generate the conflict
            var conflict = new SyncConflict(dbConflictType);

            conflict.AddRemoteRow(remoteConflictRow);

            if (localConflictRow != null)
            {
                conflict.AddLocalRow(localConflictRow);
            }

            return(conflict);
        }
Exemple #4
0
        /// <summary>
        /// We have a conflict, try to get the source row and generate a conflict
        /// </summary>
        private SyncConflict GetConflict(DmRow dmRow)
        {
            DmRow localRow = null;

            // Problem during operation
            // Getting the row involved in the conflict
            var localTable = GetRow(dmRow);

            ConflictType dbConflictType = ConflictType.ErrorsOccurred;

            // Can't find the row on the server datastore
            if (localTable.Rows.Count == 0)
            {
                if (ApplyType == DmRowState.Added)
                {
                    dbConflictType = ConflictType.RemoteInsertLocalNoRow;
                }
                else if (ApplyType == DmRowState.Modified)
                {
                    dbConflictType = ConflictType.RemoteUpdateLocalNoRow;
                }
                else if (ApplyType == DmRowState.Deleted)
                {
                    dbConflictType = ConflictType.RemoteDeleteLocalNoRow;
                }
            }
            else
            {
                // We have a problem and found the row on the server side
                localRow = localTable.Rows[0];

                var isTombstone = Convert.ToBoolean(localRow["sync_row_is_tombstone"]);

                // the row on local is deleted
                if (isTombstone)
                {
                    if (ApplyType == DmRowState.Added)
                    {
                        dbConflictType = ConflictType.RemoteInsertLocalDelete;
                    }
                    else if (ApplyType == DmRowState.Modified)
                    {
                        dbConflictType = ConflictType.RemoteUpdateLocalDelete;
                    }
                    else if (ApplyType == DmRowState.Deleted)
                    {
                        dbConflictType = ConflictType.RemoteDeleteLocalDelete;
                    }
                }
                else
                {
                    var createTimestamp = localRow["create_timestamp"] != DBNull.Value ? (long)localRow["create_timestamp"] : 0L;
                    var updateTimestamp = localRow["update_timestamp"] != DBNull.Value ? (long)localRow["update_timestamp"] : 0L;
                    switch (ApplyType)
                    {
                    case DmRowState.Added:
                        dbConflictType = updateTimestamp == 0 ? ConflictType.RemoteInsertLocalInsert : ConflictType.RemoteInsertLocalUpdate;
                        break;

                    case DmRowState.Modified:
                        dbConflictType = updateTimestamp == 0 ? ConflictType.RemoteUpdateLocalInsert : ConflictType.RemoteUpdateLocalUpdate;
                        break;

                    case DmRowState.Deleted:
                        dbConflictType = updateTimestamp == 0 ? ConflictType.RemoteDeleteLocalInsert : ConflictType.RemoteDeleteLocalUpdate;
                        break;
                    }
                }
            }
            // Generate the conflict
            var conflict = new SyncConflict(dbConflictType);

            conflict.AddRemoteRow(dmRow);

            if (localRow != null)
            {
                conflict.AddLocalRow(localRow);
            }

            localTable.Clear();

            return(conflict);
        }
Exemple #5
0
        /// <summary>
        /// Try to apply changes on the server.
        /// Internally will call ApplyInsert / ApplyUpdate or ApplyDelete
        /// </summary>
        /// <param name="dmChanges">Changes from remote</param>
        /// <returns>every lines not updated on the server side</returns>
        internal int ApplyChanges(DmView dmChanges, ScopeInfo scope, List <SyncConflict> conflicts)
        {
            int appliedRows = 0;

            foreach (var dmRow in dmChanges)
            {
                bool operationComplete = false;

                try
                {
                    if (ApplyType == DmRowState.Added)
                    {
                        operationComplete = this.ApplyInsert(dmRow, scope, false);
                        if (operationComplete)
                        {
                            UpdateMetadatas(DbCommandType.InsertMetadata, dmRow, scope);
                        }
                    }
                    else if (ApplyType == DmRowState.Modified)
                    {
                        operationComplete = this.ApplyUpdate(dmRow, scope, false);
                        if (operationComplete)
                        {
                            UpdateMetadatas(DbCommandType.UpdateMetadata, dmRow, scope);
                        }
                    }
                    else if (ApplyType == DmRowState.Deleted)
                    {
                        operationComplete = this.ApplyDelete(dmRow, scope, false);
                        if (operationComplete)
                        {
                            UpdateMetadatas(DbCommandType.UpdateMetadata, dmRow, scope);
                        }
                    }

                    if (operationComplete)
                    {
                        // if no pb, increment then go to next row
                        appliedRows++;
                    }
                    else
                    {
                        // Generate a conflict and add it
                        conflicts.Add(GetConflict(dmRow));
                    }
                }
                catch (Exception ex)
                {
                    if (this.IsUniqueKeyViolation(ex))
                    {
                        // Generate the conflict
                        var conflict = new SyncConflict(ConflictType.UniqueKeyConstraint);

                        // Add the row as Remote row
                        conflict.AddRemoteRow(dmRow);

                        // Get the local row
                        var localTable = GetRow(dmRow);
                        if (localTable.Rows.Count > 0)
                        {
                            conflict.AddLocalRow(localTable.Rows[0]);
                        }

                        conflicts.Add(conflict);

                        localTable.Clear();
                    }
                    else
                    {
                        throw;
                    }
                }
            }

            return(appliedRows);
        }