/// <summary> /// Launch apply bulk changes /// </summary> /// <returns></returns> public int ApplyBulkChanges(DmView dmChanges, ScopeInfo fromScope, List <SyncConflict> conflicts) { DbCommand bulkCommand = null; if (this.applyType == DmRowState.Added) { bulkCommand = this.GetCommand(DbObjectType.BulkInsertProcName); } else if (this.applyType == DmRowState.Modified) { bulkCommand = this.GetCommand(DbObjectType.BulkUpdateProcName); } else if (this.applyType == DmRowState.Deleted) { bulkCommand = this.GetCommand(DbObjectType.BulkDeleteProcName); } else { throw new Exception("DmRowState not valid during ApplyBulkChanges operation"); } if (Transaction != null && Transaction.Connection != null) { bulkCommand.Transaction = Transaction; } DmTable batchDmTable = dmChanges.Table.Clone(); DmTable failedDmtable = new DmTable { Culture = CultureInfo.InvariantCulture }; // Create the schema for failed rows (just add the Primary keys) this.AddSchemaForFailedRowsTable(batchDmTable, failedDmtable); int batchCount = 0; int rowCount = 0; foreach (var dmRow in dmChanges) { // Cancel the delete state to be able to get the row, more simplier if (applyType == DmRowState.Deleted) { dmRow.RejectChanges(); } // Load the datarow DmRow dataRow = batchDmTable.LoadDataRow(dmRow.ItemArray, false); // Apply the delete // is it mandatory ? if (applyType == DmRowState.Deleted) { dmRow.Delete(); } batchCount++; rowCount++; if (batchCount != 500 && rowCount != dmChanges.Count) { continue; } // Since the update and create timestamp come from remote, change name for the bulk operations batchDmTable.Columns["update_timestamp"].ColumnName = "update_timestamp"; batchDmTable.Columns["create_timestamp"].ColumnName = "create_timestamp"; // execute the batch, through the provider ExecuteBatchCommand(bulkCommand, batchDmTable, failedDmtable, fromScope); // Clear the batch batchDmTable.Clear(); // Recreate a Clone // TODO : Evaluate if it's necessary batchDmTable = dmChanges.Table.Clone(); batchCount = 0; } // Update table progress //tableProgress.ChangesApplied = dmChanges.Count - failedDmtable.Rows.Count; if (failedDmtable.Rows.Count == 0) { return(dmChanges.Count); } // Check all conflicts raised var failedFilter = new Predicate <DmRow>(row => { if (row.RowState == DmRowState.Deleted) { return(failedDmtable.FindByKey(row.GetKeyValues(DmRowVersion.Original)) != null); } else { return(failedDmtable.FindByKey(row.GetKeyValues()) != null); } }); // New View var dmFailedRows = new DmView(dmChanges, failedFilter); // Generate a conflict and add it foreach (var dmFailedRow in dmFailedRows) { conflicts.Add(GetConflict(dmFailedRow)); } int failedRows = dmFailedRows.Count; // Dispose the failed view dmFailedRows.Dispose(); // return applied rows - failed rows (generating a conflict) return(dmChanges.Count - failedRows); }