Exemple #1
0
        /// <summary>
        /// Submits one or more commands to the database reflecting the changes made to the retreived entities.
        /// If a transaction is not already specified one will be created for the duration of this operation.
        /// If a change conflict is encountered a ChangeConflictException will be thrown.
        /// You can override this method to implement common conflict resolution behaviors.
        /// </summary>
        /// <param name="failureMode">Determines how SubmitChanges handles conflicts.</param>
        public virtual void SubmitChanges(ConflictMode failureMode, IMeasureProvider measureProvider = null)
        {
            CheckDispose();
            CheckNotInSubmitChanges();
            VerifyTrackingEnabled();
            conflicts.Clear();

            try
            {
                isInSubmitChanges = true;

                if (Transactions.Transaction.Current == null && provider.Transaction == null)
                {
                    var           openedConnection = false;
                    DbTransaction transaction      = null;
                    try
                    {
                        if (provider.Connection.State == ConnectionState.Open)
                        {
                            provider.ClearConnection();
                        }
                        if (provider.Connection.State == ConnectionState.Closed)
                        {
                            provider.Connection.Open();
                            openedConnection = true;
                        }
                        transaction          = provider.Connection.BeginTransaction(IsolationLevel.ReadCommitted);
                        provider.Transaction = transaction;
                        new ChangeProcessor(services, this).SubmitChanges(failureMode, measureProvider);
                        AcceptChanges();

                        // to commit a transaction, there can be no open readers
                        // on the connection.
                        provider.ClearConnection();

                        transaction.Commit();
                    }
                    catch
                    {
                        if (transaction != null)
                        {
                            transaction.Rollback();
                        }
                        throw;
                    }
                    finally
                    {
                        provider.Transaction = null;
                        if (openedConnection)
                        {
                            provider.Connection.Close();
                        }
                    }
                }
                else
                {
                    new ChangeProcessor(services, this).SubmitChanges(failureMode, measureProvider);
                    AcceptChanges();
                }
            }
            finally
            {
                isInSubmitChanges = false;
            }
        }
Exemple #2
0
        internal void SubmitChanges(ConflictMode failureMode, IMeasureProvider measureProvider = null)
        {
            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 {
                    var tableName = item.Type.Table.TableName;
                    if (item.IsNew)
                    {
                        if (item.SynchDependentData())
                        {
                            syncDependentItems.Add(item);
                        }
                        using (measureProvider?.Measure($"Insert {tableName}"))
                        {
                            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;
                        using (measureProvider?.Measure($"Delete {tableName}"))
                        {
                            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++;
                            int ret;
                            using (measureProvider?.Measure($"Update {tableName}"))
                            {
                                ret = changeDirector.Update(item);
                            }
                            if (ret <= 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);
        }
Exemple #3
0
 /// <summary>
 /// Submits one or more commands to the database reflecting the changes made to the retreived entities.
 /// If a transaction is not already specified one will be created for the duration of this operation.
 /// If a change conflict is encountered a ChangeConflictException will be thrown.
 /// </summary>
 public void SubmitChanges(IMeasureProvider measureProvider = null)
 {
     CheckDispose();
     SubmitChanges(ConflictMode.FailOnFirstConflict, measureProvider);
 }