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; } }
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); }
public void Rollback(ModelTransaction transaction) { throw new NotSupportedException("Rollback is not supported by the ModelSaveEvent."); }
public void Perform(ModelTransaction transaction) { Instance = EnsureInstance(transaction, Instance); Instance.Save(); }
/// <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); }