Example #1
0
        void ITransactedModelEvent.Rollback(ModelTransaction transaction)
        {
            Prepare(transaction);

            ModelEventScope.Perform(() =>
            {
                ModelContext context   = Instance.Type.Context;
                ModelInstanceList list = Instance.GetList(Property);

                if (Added != null)
                {
                    foreach (ModelInstance item in Added)
                    {
                        list.Remove(item);
                    }
                }
                if (Removed != null)
                {
                    foreach (ModelInstance item in Removed)
                    {
                        list.Add(item);
                    }
                }
            });
        }
        /// <summary>
        /// Combines two or more transactions creating a new transaction.
        /// </summary>
        /// <param name="transactions"></param>
        /// <returns></returns>
        public static ModelTransaction Combine(IEnumerable <ModelTransaction> transactions)
        {
            // Get the first transaction
            ModelTransaction first = transactions.FirstOrDefault();

            if (first == null)
            {
                return(null);
            }

            // Verify that all transactions are tied to the same context
            if (transactions.Skip(1).Any(t => t.Context != first.Context))
            {
                throw new InvalidOperationException("Cannot combine ModelTransactions that are associated with different ModelContexts");
            }

            // Verify than none of the transactions are still active
            if (transactions.Any(t => t.IsActive))
            {
                throw new InvalidOperationException("Cannot combine ModelTransactions that are still active");
            }

            // Create a new transaction and combine the information from the specified transactions
            // Return the combined transactions
            var newTransaction = new ModelTransaction();

            foreach (var transaction in transactions)
            {
                // Copy new instances
                if (transaction.newInstances != null)
                {
                    if (newTransaction.newInstances == null)
                    {
                        newTransaction.newInstances = new Dictionary <string, ModelInstance>();
                    }

                    foreach (var entry in transaction.newInstances)
                    {
                        newTransaction.newInstances.Add(entry.Key, entry.Value);
                    }
                }

                // Copy events
                foreach (var evt in transaction.events)
                {
                    newTransaction.events.AddLast(evt);
                }
            }
            return(newTransaction);
        }
        /// <summary>
        /// Performs a set of previous changes, performs the specified operation, and records new changes that
        /// occur as a result of the previous changes and the specified operation.
        /// </summary>
        /// <param name="operation"></param>
        /// <param name="transaction"></param>
        /// <returns></returns>
        public ModelTransaction Perform(Action operation, ModelTransaction transaction)
        {
            // Create an event scope to track changes that occur as a result of applying previous changes
            ModelEventScope eventScope = new ModelEventScope();

            try
            {
                // Perform previous changes
                Perform();

                // Return the new changes that occurred while applying the previous changes
                return(Chain(transaction).Record(() =>
                {
                    // Allow model subscribers to be notified of the previous changes
                    eventScope.Exit();

                    // Clear the reference to the event scope to ensure it is not disposed twice
                    eventScope = null;

                    // Perform the specified operation
                    if (operation != null)
                    {
                        operation();
                    }
                }));
            }
            catch (Exception actionException)
            {
                try
                {
                    if (eventScope != null)
                    {
                        eventScope.Exit();
                    }
                }
                catch (Exception disposalException)
                {
                    throw new ModelEventScope.ScopeException(disposalException, actionException);
                }
                throw;
            }
        }
Example #4
0
        void Prepare(ModelTransaction transaction)
        {
            // Resolve the root instance
            Instance = EnsureInstance(transaction, Instance);

            // Resolve added instances
            var added = (ModelInstance[])Added;

            for (int i = 0; i < added.Length; i++)
            {
                added[i] = EnsureInstance(transaction, added[i]);
            }

            // Resolve removed instances
            var removed = (ModelInstance[])Removed;

            for (int i = 0; i < removed.Length; i++)
            {
                removed[i] = EnsureInstance(transaction, removed[i]);
            }
        }
        /// <summary>
        /// Allows multiple <see cref="ModelTransaction"/> instances to be applied in sequence, or "chained",
        /// by propogating information about newly created instances from one transaction to the next.
        /// </summary>
        public ModelTransaction Chain(ModelTransaction nextTransaction)
        {
            // Immediately exit if the transaction is being chained with itself
            if (nextTransaction == this)
            {
                return(nextTransaction);
            }

            // Propogate the new instance cache forward to the next transaction
            if (newInstances != null)
            {
                foreach (ModelInstance instance in newInstances.Values)
                {
                    nextTransaction.RegisterNewInstance(instance);
                }
            }

            // Link the next transaction to the previous transaction
            nextTransaction.PreviousTransaction = this;

            // Return the next transaction
            return(nextTransaction);
        }
Example #6
0
 public void Rollback(ModelTransaction transaction)
 {
     throw new NotSupportedException("Rollback is not supported by the ModelSaveEvent.");
 }
Example #7
0
 public void Perform(ModelTransaction transaction)
 {
     Instance = EnsureInstance(transaction, Instance);
     Instance.Save();
 }
Example #8
0
 /// <summary>
 /// Verifies that the specified <see cref="ModelInstance"/> refers to a valid real instance
 /// and if not, uses the type and id information to look up the real instance.
 /// </summary>
 /// <param name="transaction"></param>
 /// <param name="instance"></param>
 /// <returns></returns>
 protected ModelInstance EnsureInstance(ModelTransaction transaction, ModelInstance instance)
 {
     return(instance.Instance == null?transaction.GetInstance(instance.Type, instance.Id) : instance);
 }