/// <summary> /// Submits the changes to the database: executes Insert, Update and Delete queries based on the changes found in the tracked entities. /// </summary> /// <param name="failureMode">The failure mode.</param> internal void SubmitChanges(ConflictMode failureMode) { this.TrackUntrackedObjects(); // Must apply inferred deletions only after any untracked objects // are tracked this.ApplyInferredDeletions(); this.BuildEdgeMaps(); var list = this.GetOrderedList(); ValidateAll(list); int numUpdatesAttempted = 0; ChangeConflictSession conflictSession = new ChangeConflictSession(this._context); List <ObjectChangeConflict> conflicts = new List <ObjectChangeConflict>(); List <TrackedObject> deletedItems = new List <TrackedObject>(); List <TrackedObject> insertedItems = new List <TrackedObject>(); List <TrackedObject> syncDependentItems = new List <TrackedObject>(); foreach (TrackedObject item in list) { try { if (item.IsNew) { if (item.SynchDependentData()) { syncDependentItems.Add(item); } _changeDirector.Insert(item); // store all inserted items for post processing insertedItems.Add(item); } else if (item.IsDeleted) { // Delete returns 1 if the delete was successfull, 0 if the row exists // but wasn't deleted due to an OC conflict, or -1 if the row was // deleted by another context (no OC conflict in this case) numUpdatesAttempted++; int ret = _changeDirector.Delete(item); if (ret == 0) { conflicts.Add(new ObjectChangeConflict(conflictSession, item, false)); } else { // store all deleted items for post processing deletedItems.Add(item); } } else if (item.IsPossiblyModified) { if (item.SynchDependentData()) { syncDependentItems.Add(item); } if (item.IsModified) { CheckForInvalidChanges(item); numUpdatesAttempted++; if (_changeDirector.Update(item) <= 0) { conflicts.Add(new ObjectChangeConflict(conflictSession, item)); } } } } catch (ChangeConflictException) { conflicts.Add(new ObjectChangeConflict(conflictSession, item)); } if (conflicts.Count > 0 && failureMode == ConflictMode.FailOnFirstConflict) { break; } } // if we have accumulated any failed updates, throw the exception now if (conflicts.Count > 0) { // First we need to rollback any value that have already been auto-[....]'d, since the values are no longer valid on the server _changeDirector.RollbackAutoSync(); // Also rollback any dependent items that were [....]'d, since their parent values may have been rolled back foreach (TrackedObject syncDependentItem in syncDependentItems) { Debug.Assert(syncDependentItem.IsNew || syncDependentItem.IsPossiblyModified, "SynchDependent data should only be rolled back for new and modified objects."); syncDependentItem.SynchDependentData(); } this._context.ChangeConflicts.Fill(conflicts); throw CreateChangeConflictException(numUpdatesAttempted, conflicts.Count); } else { // No conflicts occurred, so we don't need to save the rollback values anymore _changeDirector.ClearAutoSyncRollback(); } // Only after all updates have been sucessfully processed do we want to make // post processing modifications to the objects and/or cache state. PostProcessUpdates(insertedItems, deletedItems); }
internal void SubmitChanges(ConflictMode failureMode) { TrackUntrackedObjects(); ApplyInferredDeletions(); BuildEdgeMaps(); var orderedList = GetOrderedList(); ValidateAll(orderedList); var num = 0; var session = new ChangeConflictSession(context); var list = new List <ObjectChangeConflict>(); var list2 = new List <TrackedObject>(); var list3 = new List <TrackedObject>(); var list4 = new List <TrackedObject>(); foreach (var item in orderedList) { try { if (item.IsNew) { if (item.SynchDependentData()) { list4.Add(item); } changeDirector.Insert(item); list3.Add(item); } else if (item.IsDeleted) { num++; if (changeDirector.Delete(item) == 0) { list.Add(new ObjectChangeConflict(session, item, false)); } else { list2.Add(item); } } else if (item.IsPossiblyModified) { if (item.SynchDependentData()) { list4.Add(item); } if (item.IsModified) { CheckForInvalidChanges(item); num++; if (changeDirector.Update(item) <= 0) { list.Add(new ObjectChangeConflict(session, item)); } } } } catch (ChangeConflictException) { list.Add(new ObjectChangeConflict(session, item)); } if (list.Count > 0 && failureMode == ConflictMode.FailOnFirstConflict) { break; } } if (list.Count > 0) { changeDirector.RollbackAutoSync(); foreach (var item2 in list4) { item2.SynchDependentData(); } context.ChangeConflicts.Fill(list); throw CreateChangeConflictException(num, list.Count); } changeDirector.ClearAutoSyncRollback(); PostProcessUpdates(list3, list2); }