/// <summary> /// Handles a change to the SourceOrderRow table. /// </summary> /// <param name="sender">The object that originated the event.</param> /// <param name="e">The event arguments.</param> private void OnSourceOrderRowChanged(object sender, SourceOrderRowChangeEventArgs e) { // When the merge is completed, this indicates that the document should be refreshed. this.isDataChanged = true; }
/// <summary> /// Handler for validating Source Order records. /// </summary> /// <param name="sender">The object that originated the event.</param> /// <param name="e">The event arguments.</param> internal static void OnSourceOrderRowValidate(object sender, SourceOrderRowChangeEventArgs e) { Decimal currentQuantity; Decimal destinationOrderQuantity; DataModelTransaction dataModelTransaction; Decimal originalQuantity; Decimal sourceOrderQuantity; WorkingOrderRow workingOrderRow; // The Business Rules will be enforced on this Source Order. Note that it is locked at the point this handler is called. SourceOrderRow sourceOrderRow = e.Row; // The action on the row determines which rule to evaluate. switch (e.Action) { case DataRowAction.Change: // Reject the operation if the Working Order is overcommitted with a destination. Note that the order of the evaluation is important for // efficiency. That is, there is no need to sum up the Source and Destination Orders, which requires locking several records, if the Source // Order quantity has been incremented as there's no chance it will be over committed. originalQuantity = (Decimal)sourceOrderRow[DataModel.SourceOrder.OrderedQuantityColumn, DataRowVersion.Original]; currentQuantity = (Decimal)sourceOrderRow[DataModel.SourceOrder.OrderedQuantityColumn, DataRowVersion.Current]; if (originalQuantity < currentQuantity) { // A middle tier context is required to lock the rows so the quantities can be aggregated. dataModelTransaction = DataModelTransaction.Current; // Once its determined that the quantity has increased, the Working Order row will need to be locked to examine the aggregate values of the // source and Destination Orders. workingOrderRow = e.Row.WorkingOrderRow; workingOrderRow.AcquireReaderLock(dataModelTransaction); // This is an illegal operation if the quantity sent to a destination is greater than the quantity ordered. sourceOrderQuantity = WorkingOrder.GetSourceOrderQuantity(dataModelTransaction, workingOrderRow); destinationOrderQuantity = WorkingOrder.GetDestinationOrderQuantity(dataModelTransaction, workingOrderRow); if (sourceOrderQuantity < destinationOrderQuantity) { throw new FaultException <DestinationQuantityFault>( new DestinationQuantityFault(workingOrderRow.WorkingOrderId, sourceOrderQuantity, destinationOrderQuantity)); } } break; case DataRowAction.Delete: // A middle tier context is required to lock the rows so the quantities can be aggregated. dataModelTransaction = DataModelTransaction.Current; // The main idea of this trigger is to prevent the over commitment of a Working Order when a Source Order is deleted. At this point, the // Source Order is deleted, so the original record must be used to find the parent Working Order that is effected. sourceOrderRow = e.Row; try { DataModel.DataLock.EnterReadLock(); workingOrderRow = ((WorkingOrderRow)(sourceOrderRow.GetParentRow(DataModel.SourceOrder.WorkingOrderSourceOrderRelation, DataRowVersion.Original))); } finally { DataModel.DataLock.ExitReadLock(); } // Lock the working order row while some aggregate values are calculated. workingOrderRow.AcquireReaderLock(dataModelTransaction); // Reject the operation if the Working Order is overcommitted with a destination. sourceOrderQuantity = WorkingOrder.GetSourceOrderQuantity(dataModelTransaction, workingOrderRow); destinationOrderQuantity = WorkingOrder.GetDestinationOrderQuantity(dataModelTransaction, workingOrderRow); if (sourceOrderQuantity < destinationOrderQuantity) { throw new FaultException <DestinationQuantityFault>( new DestinationQuantityFault(workingOrderRow.WorkingOrderId, sourceOrderQuantity, destinationOrderQuantity)); } break; } }