public ErrorCode DeleteRow(DataModel dataModel, DataModelTransaction transaction, DebtRuleRow debtRuleRow) { debtRuleRow.AcquireReaderLock(transaction); DebtRuleMapRow[] debtRuleMaps = debtRuleRow.GetDebtRuleMapRows(); if (debtRuleRow.GetDebtClassRows().Length != 0) { return(ErrorCode.AccessDenied); } debtRuleRow.ReleaseReaderLock(transaction.TransactionId); foreach (DebtRuleMapRow debtRuleMapRow in debtRuleMaps) { debtRuleMapRow.AcquireReaderLock(transaction); if (!DataModelFilters.HasAccess(transaction, TradingSupport.UserId, debtRuleMapRow.DebtClassId, AccessRight.Write)) { return(ErrorCode.AccessDenied); } debtRuleMapRow.ReleaseReaderLock(transaction.TransactionId); } debtRuleRow.AcquireWriterLock(transaction); dataModel.DestroyDebtRule(new object[] { debtRuleRow.DebtRuleId }, debtRuleRow.RowVersion); debtRuleRow.ReleaseLock(transaction.TransactionId); return(ErrorCode.Success); }
/// <summary> /// Delete a debt holder /// </summary> /// <returns>True for sucess</returns> public override ErrorCode Delete(ConsumerTrust record) { DataModel dataModel = new DataModel(); DataModelTransaction transaction = DataModelTransaction.Current; if (record.RowId == null || DataModel.ConsumerTrust.ConsumerTrustKey.Find(record.RowId) == null) { return(ErrorCode.RecordNotFound); } ConsumerTrustRow consumerTrust = DataModel.ConsumerTrust.ConsumerTrustKey.Find(record.RowId); consumerTrust.AcquireReaderLock(transaction); Guid debtId = consumerTrust.ConsumerTrustId; ConsumerRow consumer = consumerTrust.ConsumerRow; DebtRuleRow debtRule = consumerTrust.DebtRuleRow; consumerTrust.ReleaseReaderLock(transaction.TransactionId); #if false // If we switch from explicitly deleting the working order to explicitly deleting the security, then we need this. if (!TradingSupport.HasAccess(transaction, debtId, AccessRight.Write)) { return(ErrorCode.AccessDenied); } #endif consumerTrust.AcquireWriterLock(transaction); if (consumerTrust.RowState != DataRowState.Deleted && consumerTrust.RowState != DataRowState.Detached) { dataModel.DestroyConsumerTrust(new object[] { consumerTrust.ConsumerTrustId }, record.RowVersion); } consumerTrust.ReleaseWriterLock(transaction.TransactionId); consumer.AcquireWriterLock(transaction); if (consumer.RowState != DataRowState.Deleted && consumer.RowState != DataRowState.Detached) { dataModel.DestroyConsumer(new object[] { consumer.ConsumerId }, consumer.RowVersion); } consumer.ReleaseWriterLock(transaction.TransactionId); if (debtRule != null) { debtRule.AcquireReaderLock(transaction); if (debtRule.RowState != DataRowState.Deleted && debtRule.RowState != DataRowState.Detached && debtRule.GetDebtRuleMapRows().Length == 0) { DebtRulePersistence debtRulePersistence = new DebtRulePersistence(); Guid debtRuleId = debtRule.DebtRuleId; long rowVersion = debtRule.RowVersion; debtRule.ReleaseReaderLock(transaction.TransactionId); debtRulePersistence.Delete(new Records.DebtRule { RowId = debtRuleId, RowVersion = rowVersion }); } else { debtRule.ReleaseReaderLock(transaction.TransactionId); } } return(ErrorCode.Success); }
public ConsumerTrustMatchInfo(DataModelTransaction dataModelTransaction, WorkingOrderRow workingOrderRow) { // Initialize the object this.PaymentMethodTypes = new List <Guid>(); // These rows are required for navigating through the asset. Locks are acquired temporarily for them and released as soon as the Consumer Debt // information is collected. BlotterRow blotterRow = null; SecurityRow securityRow = null; ConsumerTrustRow consumerTrustRow = null; // The working order row is where everything starts. This is the asset that is to be matched against another. workingOrderRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); try { // The working order identifier is used when creating matches. this.WorkingOrderId = workingOrderRow.WorkingOrderId; // The underlying security is a Consumer Debt record. securityRow = workingOrderRow.SecurityRowByFK_Security_WorkingOrder_SecurityId; // The blotter row needs to be examined for this cross. blotterRow = workingOrderRow.BlotterRow; } finally { workingOrderRow.ReleaseReaderLock(dataModelTransaction.TransactionId); } securityRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); try { consumerTrustRow = securityRow.GetConsumerTrustRows()[0]; } finally { securityRow.ReleaseReaderLock(dataModelTransaction.TransactionId); } DebtRuleRow debtRuleRow = null; // This row contains the actual asset that is to be matched. consumerTrustRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); try { // The savings balance is used when calculating the status of the match (whether there is enough funds in the account). this.SavingsBalance = consumerTrustRow.SavingsBalance; if (consumerTrustRow.IsDebtRuleIdNull() == false) { // At this point a rule override was found on an asset and there's no need to search the Entity hierarchy. debtRuleRow = consumerTrustRow.DebtRuleRow; } } finally { consumerTrustRow.ReleaseReaderLock(dataModelTransaction.TransactionId); } // This will attempt to find the debt rule associated with this credit card. If there is no rule explicitly associated with the asset, // then the entity hierarchy is searched until a debt class is found that contains a rule. When the rule is found, the values in that rule // will become the opening bid. DebtClassRow[] blotterRowDebtClassRows = null; blotterRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); try { // The blotter is required for adding matches to the data model once they are found. this.BlotterId = blotterRow.BlotterId; if (debtRuleRow == null) { blotterRowDebtClassRows = blotterRow.GetDebtClassRows(); } } finally { blotterRow.ReleaseReaderLock(dataModelTransaction.TransactionId); } if (debtRuleRow == null) { // At this point, the asset hasn't got an explicit rule, so the hierarchy will need to be searched. There is only going to be one Debt // Class element associated with this blotter, but the iteration is an easier construct to work with than the equivalent array logic // for a single element. foreach (DebtClassRow debtClassRow in blotterRowDebtClassRows) { // This variable will keep track of our current location as we crawl up the hierarchy. DebtClassRow currentDebtClassRow = debtClassRow; DebtClassRow nextDebtClassRow = null; // This will crawl up the hierarchy until a Debt Class is found with a rule. This rule will provide the opening values for the // bid on this negotiation. do { // This will lock the current item in the hierarchy so it can be examined for a rule or, failing that, a parent element. currentDebtClassRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); Guid currentDebtClassRowDebtClassId; try { currentDebtClassRowDebtClassId = currentDebtClassRow.DebtClassId; if (currentDebtClassRow.IsDebtRuleIdNull() == false) { // At this point we have finally found a debt rule that can be used to start the negotiations. debtRuleRow = currentDebtClassRow.DebtRuleRow; } } finally { // The current Debt Class can be released. At this point, every record that was locked to read the hiearchy has been // released and the loop can either exit (when a rule is found) or move on to the parent Debt Class. currentDebtClassRow.ReleaseReaderLock(dataModelTransaction.TransactionId); } // If the current Debt Class has no rule then the Entity Hierarchy is used to find the parent element. if (debtRuleRow == null) { EntityTreeRow[] entityTreeRows; // The entity is the root of all objects in the hierarchy. From this object the path to the parent Debt Class can be // navigated. EntityRow entityRow = DataModel.Entity.EntityKey.Find(currentDebtClassRowDebtClassId); // Each entity needs to be locked before the relation can be used. entityRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); try { entityTreeRows = entityRow.GetEntityTreeRowsByFK_Entity_EntityTree_ChildId(); } finally { // Finaly, the current entity is released. This allows us to finally move on to the next level of the hierarchy // without having to hold the locks for the entire transaction. entityRow.ReleaseReaderLock(dataModelTransaction.TransactionId); } // This will find each relation in the hierarchy which uses the current node as a child. foreach (EntityTreeRow entityTreeRow in entityTreeRows) { EntityRow parentEntityRow; // Lock the relation down before navigating to the parent. entityTreeRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); try { // This is the parent entity of the current entity in the crawl up the hierarchy. parentEntityRow = entityTreeRow.EntityRowByFK_Entity_EntityTree_ParentId; } finally { // The relationship record is released after each level of the hierarchy is examined for a parent. entityTreeRow.ReleaseReaderLock(dataModelTransaction.TransactionId); } BlotterRow[] blotterRows; // The parent entity must be locked befor it can be checked for blotters and then, in turn, debt // classes. parentEntityRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); try { blotterRows = parentEntityRow.GetBlotterRows(); } finally { // The parent Entity record is released after each level of the hiearchy is examined for a parent. parentEntityRow.ReleaseReaderLock(dataModelTransaction.TransactionId); } // In practice, there will be zero or one blotter rows. The iteration makes it easier to check both // conditions. foreach (BlotterRow parentBlotterRow in blotterRows) { DebtClassRow[] parentBlotterRowDebtClassRows; // The blotter must be locked before iterating through the Debt Classes that may be associated // with the blotter. parentBlotterRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); try { parentBlotterRowDebtClassRows = parentBlotterRow.GetDebtClassRows(); } finally { // The locks are released after the each level of the hierarchy is checked. parentBlotterRow.ReleaseReaderLock(dataModelTransaction.TransactionId); } // Each blotter can have zero or one Debt Classes associated with it. This is a long an // tortuous way to finally get to the parent Debt Class. foreach (DebtClassRow parentDebtClassRow in parentBlotterRowDebtClassRows) { // Now that we've finally found the parent Debt Class, it will become the parent on // the next pass through the hierarchy. Note that the locks are released each time we // pass through a level of the hierarchy. nextDebtClassRow = parentDebtClassRow; } } } } // Now that all the locks are released, the parent Debt Class becomes the current one for the next level up in the hierarchy. // This algorithm will keep on climbing through the levels until a rule is found or the hierarchy is exhausted. currentDebtClassRow = nextDebtClassRow; } while(debtRuleRow == null && currentDebtClassRow != null); } } // The data is copied out of the Debt Rule when one is found in the Entity hierarchy. if (debtRuleRow != null) { DebtRulePaymentMethodRow[] debtRuleRowDebtRulePaymentMethodRows; // At this point we found a rule that can be used for the opening bid of a settlement. debtRuleRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); try { // These values are used in the opening bid of a negotiated settlement. this.PaymentLength = debtRuleRow.PaymentLength; this.PaymentStartDateLength = debtRuleRow.PaymentStartDateLength; this.PaymentStartDateUnitId = debtRuleRow.PaymentStartDateUnitId; this.SettlementValue = debtRuleRow.SettlementValue; this.SettlementUnitId = debtRuleRow.SettlementUnitId; debtRuleRowDebtRulePaymentMethodRows = debtRuleRow.GetDebtRulePaymentMethodRows(); } finally { // A lock on the Debt Rule is no longer required. debtRuleRow.ReleaseReaderLock(dataModelTransaction.TransactionId); } // This will copy each of the payment methods that are available for this settlement. Note that the table rows are locked only long // enough to acquire the item, then released. foreach (DebtRulePaymentMethodRow debtRulePaymentMethodRow in debtRuleRowDebtRulePaymentMethodRows) { debtRulePaymentMethodRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); try { this.PaymentMethodTypes.Add(debtRulePaymentMethodRow.PaymentMethodTypeId); } finally { debtRulePaymentMethodRow.ReleaseReaderLock(dataModelTransaction.TransactionId); } } } }