internal static void CheckForAdapterRowIds(DbSyncAdapterCollection adapters) { List <string> list = new List <string>(); foreach (DbSyncAdapter dbSyncAdapter in (Collection <DbSyncAdapter>)adapters) { if (dbSyncAdapter.RowIdColumns.Count == 0) { list.Add(dbSyncAdapter.TableName); } } if (list.Count <= 0) { return; } StringBuilder stringBuilder = new StringBuilder(); string str1 = string.Empty; foreach (string str2 in list) { stringBuilder.Append(str1 + str2); str1 = ", "; } SyncTracer.Error(SyncResource.FormatString("MissingAdapterRowIdColumns", new object[0]), new object[1] { (object)((object)stringBuilder).ToString() }); throw new DbSyncException(SyncResource.FormatString("MissingAdapterRowIdColumns", new object[1] { (object)((object)stringBuilder).ToString() })); }
// // ****** Methods for adding unsorted data // public void AddUnsortedDataSet(DataSet dataSet) { // for each table in the DataSet foreach (DataTable curTable in dataSet.Tables) { int numColumns = curTable.Columns.Count; // this table should already be in the list of added // tables SortedTable sortedTable; if (!_sortedTables.TryGetValue(curTable.TableName, out sortedTable)) { SyncTracer.Error("Cannot Apply Changes since Adapters are missing for the following tables: {0}. " + "Please ensure that the local and global names on the Adapters are set properly.", curTable); throw new DbSyncException("MissingProviderAdapter"); } if (sortedTable._schema == null) { // add a new row storage dictionary and schema if we // need one sortedTable._schema = curTable.Clone(); Debug.Assert(sortedTable._schema.DataSet == null); sortedTable._rows = new SortedDictionary <SyncId, SortedRow>(_syncIdComparer); } if (curTable.Rows.Count == 0) { continue; } object[] idColVals = new object[sortedTable._idCols.Count]; // for each row foreach (DataRow curRow in curTable.Rows) { DataRowVersion viewVersion = (curRow.RowState == DataRowState.Deleted) ? DataRowVersion.Original : DataRowVersion.Current; for (int idx = 0; idx < idColVals.Length; idx += 1) { idColVals[idx] = curRow[sortedTable._idCols[idx], viewVersion]; } // Add the row to this tables row storage dictionary SyncId curRowId = SyncUtil.InitRowId(curTable.TableName, idColVals); // Note: There is an issue with batching in the provider which causes the same primary key to be repeated across files. // This crashes the .Add call below. To work-around this problem, we need to check if the key already exists. // If it does, then remove it and add it again so that the latest record is always used. if (sortedTable._rows.ContainsKey(curRowId)) { sortedTable._rows.Remove(curRowId); } sortedTable._rows.Add(curRowId, new SortedRow(curRow, numColumns)); } } }
/// #DOWNLOAD (not in batches) public SpSyncAnchor SelectAll(SpSyncAnchor anchor, int rowLimit, DataTable dataTable, SpConnection connection) { if (anchor == null) { throw new ArgumentNullException("anchor"); } if (connection == null) { throw new ArgumentNullException("connection"); } if (dataTable == null) { throw new ArgumentNullException("dataTable"); } QueryOptions queryOptions = new QueryOptions() { PagingToken = anchor.PagingToken, DateInUtc = false }; IEnumerable <string> viewFields = GetViewFields(); ListItemCollection listItems = connection.GetListItems( this.ListName, this.ViewName, this.FilterClause, viewFields, IncludeProperties, rowLimit, queryOptions); if (dataTable != null) { foreach (ListItem item in listItems) { DataRow row = dataTable.NewRow(); Exception e; MapListItemToDataRow(item, row, out e); if (e != null) { if (SyncTracer.IsErrorEnabled()) { SyncTracer.Error(e.ToString()); } } dataTable.Rows.Add(row); } } dataTable.AcceptChanges(); return(CalculateNextAnchor(anchor, listItems.NextPage)); }
/// <summary> /// Gets a SyncSchema object created by consulting the database, namely by filling the datatables from the SyncAdapters /// </summary> /// <param name="tableNames">the names of the tables to be included in the schema</param> /// <param name="missingTables">the names of the missing tables not found in the set of the SyncAdapters</param> /// <returns>the SyncSchema object</returns> protected virtual SyncSchema GetSchemaFromDatabase(Collection <string> tableNames, out Collection <string> missingTables) { SyncSchema schema = new SyncSchema(); schema.SchemaDataSet = new DataSet(); schema.SchemaDataSet.Locale = CultureInfo.InvariantCulture; missingTables = new Collection <string>(); Connection.Open(); foreach (string tableName in tableNames) { SpSyncAdapter adapter = null; if (SyncAdapters.Contains(tableName)) { adapter = SyncAdapters[tableName]; } if (adapter != null) { DataTable dataTable = null; try { dataTable = adapter.FillSchema(dataTable, Connection); dataTable.TableName = tableName; schema.SchemaDataSet.Tables.Add(dataTable); } catch (Exception e) { missingTables.Add(tableName); if (SyncTracer.IsErrorEnabled()) { SyncTracer.Error(e.ToString()); } } } else { missingTables.Add(tableName); } } Connection.Close(); if (missingTables.Count == 0) { missingTables = null; } return(schema); }
internal static void TryOpenConnection(IDbConnection connection) { for (int index = 0; index < 6; ++index) { try { if (index > 0) { SyncTracer.Info("Retrying opening connection, attempt {0} of {1}.", new object[2] { (object)index, (object)5 }); } connection.Open(); SqlConnection connection1 = connection as SqlConnection; if (connection1 == null) { break; } using (SqlCommand sqlCommand = new SqlCommand("Select 1", connection1)) { sqlCommand.ExecuteScalar(); break; } } catch (SqlException ex) { if (index == 5) { SyncTracer.Error("Open connection failed after max retry attempts, due to exception: {0}", new object[1] { (object)ex.Message }); throw; } else if (!SyncUtil.RetryLitmus(ex)) { SyncTracer.Error("Open connection failed on attempt {0} of {1}, due to unretryable exception: {2}", (object)(index + 1), (object)5, (object)ex.Message); throw; } else { SyncTracer.Warning("Open connection failed on attempt {0} of {1}, due to retryable exception: {2}", (object)(index + 1), (object)5, (object)ex.Message); Thread.Sleep(100 * (int)Math.Pow(2.0, (double)index)); } } } }
internal static void ExecuteNonQueryWithNewTransaction(IDbCommand command) { for (int index = 0; index < 6; ++index) { try { if (index > 0) { SyncTracer.Info("Retrying SyncUtil.ExecuteNonQueryWithNewTransaction, attempt {0} of {1}.", new object[2] { (object)index, (object)5 }); SyncUtil.OpenConnection(command.Connection); } using (IDbTransaction dbTransaction = command.Connection.BeginTransaction()) { command.Transaction = dbTransaction; command.ExecuteNonQuery(); dbTransaction.Commit(); break; } } catch (DbException ex) { if (index == 5) { SyncTracer.Error("SyncUtil.ExecuteNonQueryWithNewTransaction failed after max retry attempts, due to exception: {0}", new object[1] { (object)ex.Message }); throw; } else { SyncTracer.Warning("SyncUtil.ExecuteNonQueryWithNewTransaction failed on attempt {0} of {1}, due to retryable exception: {2}", (object)index, (object)5, (object)ex.Message); Thread.Sleep(100 * (int)Math.Pow(2.0, (double)index)); } } } }
/// <summary> /// /// </summary> /// <param name="inserts"></param> /// <param name="updates"></param> /// <param name="deletes"></param> /// <param name="connection"></param> /// #UPLOAD 3 public void Update(DataTable changes, SpConnection connection, out Collection <SyncConflict> errors) { errors = new Collection <SyncConflict>(); if (changes == null) { throw new ArgumentNullException("changes"); } if (connection == null) { throw new ArgumentNullException("connection"); } int _batchSize = 25; int segmentsCount = (int)Math.Round(Math.Ceiling((double)changes.Rows.Count / _batchSize), 0); if (IgnoreColumnsOnUpdate != null) { // case to be handled // cannot remove Sharepoint ID. // cannot remove Primary Key of DataTable? foreach (string ignoredColumn in IgnoreColumnsOnUpdate) { string clientColumn = GetClientColumnFromServerColumn(ignoredColumn); if (clientColumn != null && changes.Columns.Contains(clientColumn)) { changes.Columns.Remove(clientColumn); } } } DataTable changesTotal = changes.Copy(); for (int i = 0; i < segmentsCount; i++) { changes.Rows.Clear(); CopyRows(changesTotal, changes, i * _batchSize, _batchSize); //SEND SEGMENT UpdateBatch batch = new UpdateBatch(); string clientIdColumn = GetClientColumnFromServerColumn("ID"); if (!changes.Columns.Contains(clientIdColumn)) { throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, Messages.ColumnIDNotContained, clientIdColumn)); } IDictionary <int, DataRow> IdMapping = new Dictionary <int, DataRow>(); foreach (DataRow row in changes.Rows) { UpdateItem u = batch.CreateNewItem(); switch (row.RowState) { case DataRowState.Added: u.Command = UpdateCommands.Insert; break; case DataRowState.Deleted: u.Command = UpdateCommands.Delete; break; case DataRowState.Modified: u.Command = UpdateCommands.Update; break; case DataRowState.Unchanged: continue; } if (u.Command == UpdateCommands.Delete) { row.RejectChanges(); } if (u.Command != UpdateCommands.Insert) { if (!(row[clientIdColumn] is DBNull)) { u.ListItemID = (int)row[clientIdColumn]; } else { continue; } } if (u.Command != UpdateCommands.Delete) { ListItem item = new ListItem(); Exception e; MapDataRowToListItem(row, item, out e); u.ChangedItemData = item; if (e != null && SyncTracer.IsErrorEnabled()) { SyncTracer.Error(e.ToString()); } } batch.Add(u); IdMapping[u.ID] = row; if (u.Command == UpdateCommands.Delete) { row.Delete(); } } if (batch.Count != 0) { //try //{ UpdateResults results = connection.UpdateListItems(this.ListName, batch); // FIX: errors must be handled appropriately foreach (UpdateResult r in results) { if (!r.IsSuccess()) { if (!IdMapping.ContainsKey(r.UpdateItemID)) { throw new InvalidOperationException( String.Format(CultureInfo.CurrentCulture, Messages.NoIDMapping, r.UpdateItemID)); } DataRow clientRow = IdMapping[r.UpdateItemID]; errors.Add(CreateSyncError(r, clientRow)); } } //} //catch (Exception ex) //{ ////usually connection error // foreach (UpdateItem item in batch) // { // if (!IdMapping.ContainsKey(item.ID)) // throw new InvalidOperationException( // String.Format(CultureInfo.CurrentCulture, Messages.NoIDMapping, r.UpdateItemID)); // DataRow clientRow = IdMapping[item.ID]; // errors.Add(CreateSyncError(new UpdateResult(, clientRow)); // } //} } //END SEND SEGMENT } if (errors.Count == 0) { errors = null; } }
/// #DOWNLOAD public SpSyncAnchor SelectIncremental(SpSyncAnchor anchor, int rowLimit, SpConnection connection, DataTable changeTable) {//#DOWNLOAD in batches - step 3 if (anchor == null) { throw new ArgumentNullException("anchor"); } if (connection == null) { throw new ArgumentNullException("connection"); } QueryOptions queryOptions = new QueryOptions() { PagingToken = anchor.PagingToken, DateInUtc = false }; IEnumerable <string> viewFields = GetViewFields(); ChangeBatch changes = connection.GetListItemChangesSinceToken( this.ListName, this.ViewName, FilterClause, viewFields, IncludeProperties, rowLimit, queryOptions, anchor.NextChangesToken); foreach (ListItem item in changes.ChangedItems) { DataRow row = changeTable.NewRow(); Exception e; MapListItemToDataRow(item, row, out e); if (e != null) { if (SyncTracer.IsErrorEnabled()) { SyncTracer.Error(e.ToString()); } } changeTable.Rows.Add(row); row.AcceptChanges(); row.SetModified(); } foreach (ChangeItem item in changes.ChangeLog) { string clientColumnName = GetClientColumnFromServerColumn("ID"); if (ChangeCommands.IsDelete(item.Command)) { DataRow row = changeTable.NewRow(); // FIX: Probably the ID is not mapped at all to the client table row[clientColumnName] = item.ListItemID; changeTable.Rows.Add(row); row.AcceptChanges(); row.Delete(); } } return(CalculateNextAnchor(anchor, changes)); }
/// <summary> /// Fills the tables insertTbl, updateTbl, deleteTbl with the changes fetch by the sharepoint server /// since a change token /// </summary> /// <param name="anchor">the anchor to specify the change token</param> /// <param name="rowLimit">the maximum number of rows to fetch </param> /// <param name="connection">the connection to the sharepoint server</param> /// <param name="insertTbl">the DataTable to append the rows that have been inserted</param> /// <param name="updateTbl">the DataTable to append the rows that have been updated</param> /// <param name="deleteTbl">the DataTable to append the rows that have been deleted</param> /// <remarks> /// Because of the response of the sharepoint changelog we cannot identify the updates from the inserts. /// So, no record will be added to the updateTbl. /// </remarks> /// <returns>the new SpSyncAnchor object to be used in subsequent calls</returns> /// #DOWNLOAD public SpSyncAnchor SelectIncremental(SpSyncAnchor anchor, int rowLimit, SpConnection connection, DataTable insertTbl, DataTable updateTbl, DataTable deleteTbl) { if (anchor == null) { throw new ArgumentNullException("anchor"); } if (connection == null) { throw new ArgumentNullException("connection"); } QueryOptions queryOptions = new QueryOptions() { PagingToken = anchor.PagingToken, DateInUtc = false }; IEnumerable <string> viewFields = GetViewFields(); ChangeBatch changes = connection.GetListItemChangesSinceToken( this.ListName, this.ViewName, FilterClause, viewFields, IncludeProperties, rowLimit, queryOptions, anchor.NextChangesToken); if (insertTbl != null) { foreach (ListItem item in changes.ChangedItems) { DataRow row = insertTbl.NewRow(); Exception e; MapListItemToDataRow(item, row, out e); if (e != null) { if (SyncTracer.IsErrorEnabled()) { SyncTracer.Error(e.ToString()); } } insertTbl.Rows.Add(row); } } // FIX: Cannot identify the updates from the inserts. if (deleteTbl != null) { foreach (ChangeItem item in changes.ChangeLog) { if (ChangeCommands.IsDelete(item.Command)) { DataRow row = deleteTbl.NewRow(); // FIX: Probably the ID is not mapped at all to the client table row[deleteTbl.PrimaryKey[0]] = item.ListItemID; deleteTbl.Rows.Add(row); } } } insertTbl.AcceptChanges(); // COMMITCHANGES updateTbl.AcceptChanges(); deleteTbl.AcceptChanges(); return(CalculateNextAnchor(anchor, changes)); }
/// #UPLOAD 2 private void ApplyChangesInternal(SyncGroupMetadata groupMetadata, DataSet dataSet, SyncSession syncSession, SyncContext syncContext) { SyncStage syncStage = SyncStage.UploadingChanges; foreach (SyncTableMetadata tableMetadata in groupMetadata.TablesMetadata) { SpSyncAdapter adapter = null; if (this.SyncAdapters.Contains(tableMetadata.TableName)) { adapter = this.SyncAdapters[tableMetadata.TableName]; } if (adapter == null) { throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Messages.InvalidTableName, tableMetadata.TableName)); } // SpSyncAnchor anchor if (!dataSet.Tables.Contains(tableMetadata.TableName)) { throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Messages.TableNotInSchema, tableMetadata.TableName)); } SyncTableProgress tableProgress = syncContext.GroupProgress.FindTableProgress(tableMetadata.TableName); DataTable dataTable = dataSet.Tables[tableMetadata.TableName]; try { Collection <SyncConflict> conflicts; int changesCount = dataTable.Rows.Count; adapter.Update(dataTable, Connection, out conflicts); if (conflicts != null) { foreach (SyncConflict conflict in conflicts) { ApplyChangeFailedEventArgs failureArgs = new ApplyChangeFailedEventArgs(tableMetadata, conflict, null, syncSession, syncContext, Connection, null); OnApplyChangeFailed(failureArgs); if (failureArgs.Action == ApplyAction.Continue) { if (conflict != null) { tableProgress.ChangesFailed++; tableProgress.Conflicts.Add(conflict); } } } } tableProgress.ChangesApplied = changesCount - tableProgress.ChangesFailed; } catch (Exception e) { SyncConflict conflict = new SyncConflict(ConflictType.ErrorsOccurred, SyncStage.UploadingChanges) { ErrorMessage = e.Message + ", InnerException:" + e.InnerException.ToString(), ServerChange = dataTable, ClientChange = dataTable }; ApplyChangeFailedEventArgs failureArgs = new ApplyChangeFailedEventArgs(tableMetadata, conflict, null, syncSession, syncContext, Connection, null); OnApplyChangeFailed(failureArgs); // handle errors? if (SyncTracer.IsErrorEnabled()) { SyncTracer.Error(e.ToString()); } } SyncProgressEventArgs args = new SyncProgressEventArgs(tableMetadata, tableProgress, groupMetadata, syncContext.GroupProgress, syncStage); OnSyncProgress(args); } }