Overriding the Persist Method

You generally override the PXGraph.Persist method when you need to implement one of the following scenarios:

  • Verifying the changes made to records of an entity type before persisting them to the database, and preventing the changes from being persisted if the verification fails.
  • Verifying the changes made to records of an entity type that are to be persisted to the database, while adding some changes that should also be persisted in the same transaction in which the persist operation is executed.
  • Performing a validation or other operation right before a transaction is closed.
  • Performing an operation right after a change is successfully persisted to the database. These operations usually involve tasks that are not part of the transaction in which the persist operation is executed—such as resetting a custom cache, querying the database, or displaying a message to the user.

However, when you are dealing with these scenarios, we recommend that you not override the PXGraph.Persist method directly because this approach can be error prone. Instead, we recommend that you use the appropriate targeted override of this method. To give you more granular control, the PXGraph.Persist method has the following targeted overrides:

  • bool PXGraph.PrePersist(): Makes it possible for you to define the logic that should be executed before the definition of the persisting logic. This method is triggered before a transaction is opened. The base implementation of this method raises the PXGraph.BeforePersist event.
  • void PXGraph.PerformPersist(IPersistPerformer persister): Provides the ability for you to change the order and composition of the caches that should be persisted within the definition of the persisting logic. This method is triggered within an open transaction.
  • void PXGraph.PreCommit(): Gives you the ability to inject some logic just before a transaction is closed. This method is triggered within an open transaction. The base implementation of this method raises the PXGraph.OnBeforeCommit event.
  • void PXGraph.PostPersist(): Delivers the capability for you to define the logic that should be executed after the definition of the persisting logic. This method is triggered after a transaction has been closed. The base implementation of this method raises the PXGraph.AfterPersist event.
Note: When you override any of the above methods, you must call the base version of the method. The only exception to this rule is when you need to suppress the base logic for some reason.

By using the methods described in the preceding list, you can inject your logic into the existing logic of the persist process without affecting the existing logic. This approach makes your code less error prone.

The following code shows an example of how you can inject your custom logic in a graph via a graph extension by using the targeted overrides of the PXGraph.Persist method.

protected override bool PrePersist()
{
 if (Document.Current != null && Document.Current.Hold == false)
   {
       foreach (POReceiptLine poReceiptLine in transactions.Select())
         if (poReceiptLine.ReceiptQty == 0m && Document.Current.ReceiptType 
              == POReceiptType.TransferReceipt)
                 transactions.Delete(poReceiptLine);

       ValidateDuplicateSerialsOnDropship();
   }

    /* Use a graph extension to insert some custom logic
       by overriding the PXGraph.PrePersist method */
   return base.PrePersist();
}

protected override void PostPersist()
{
 base.PostPersist();
 this.poLinesSelection.Cache.Clear();
 this.openOrders.Cache.Clear();
}

The following code shows an example of how the bool PXGraph.PrePersist() method can be overridden in a graph extension to define the custom logic for the preceding code example.

[PXOverride]
public bool PrePersist(Func<bool> base_PrePersist)
{
 if (!base_PrePersist())
      return false;
 
 var linesCache = Base.transactions.Cache;
 var modifiedLines = linesCache.Updated.Concat_(linesCache.Inserted);
 
 foreach (POReceiptLine line in modifiedLines)
      SyncUnassigned(line);

 return true;
}

The following sections provide some usage examples for the methods described in the preceding list.

Using the bool PXGraph.PrePersist() Method

The following code example shows how you can use the bool PXGraph.PrePersist() method in a graph when you need to perform both a check and an assignment operation before the persist operation.

protected override bool PrePersist()
{
 if (setup.Current != null && string.IsNullOrEmpty(setup.Current.DfltLotSerClassID) 
      && !IsFeatureInstalled<FeaturesSet.lotSerialTracking>())
   {
       setup.Current.DfltLotSerClassID = INLotSerClass.GetDefaultLotSerClass(this);
   }
 return base.PrePersist();
}

The following code example shows how you may use the bool PXGraph.PrePersist() method in a graph when you need to perform a validation before the persist operation.

protected override bool PrePersist()
{
 if (CMSetup.Select().Count == 0)
      throw new PXException(CS.Messages
             .RequiredConfigurationDataIsNotEnteredOnCurrencyManagementPreferencesForm);

 return base.PrePersist();
}

Using the void PXGraph.PerformPersist(IPersistPerformer persister) Method

Suppose that you need to use a graph extension to find some records of some specific entities and persist them to the database in the scope of another graph. This graph extension should first search for those records and store them into a field by overriding the bool PXGraph.PrePersist() method. Then at the end of the void PXGraph.PerformPersist(IPersistPerformer persister) method, the graph extension should pass those stored records to a special method that creates a new graph in which those records should be saved; the graph extension then saves them. Since you are calling this special method in the scope of the void PXGraph.PerformPersist(IPersistPerformer persister) method, it is automatically available in the scope of the same transaction that is used in the initial graph (the one that overrides the persist methods). Hence, you do not need to open another transaction.

The following code example shows how you can use the void PXGraph.PerformPersist(IPersistPerformer persister) method in a graph extension to implement the scenario described above.

[PXOverride]
public bool PrePersist(Func<bool> base_PrePersist)
{
 _affectedOrders = GetAffectedEntities().ToArray();
 return base_PrePersist();
}
 
[PXOverride]
public void PerformPersist(PXGraph.IPersistPerformer persister,
 Action<PXGraph.IPersistPerformer> base_PerformPersist)
{
 base_PerformPersist(persister);
 
 if (_affectedOrders != null)
 {
     ProcessAffectedEntities(_affectedOrders);
     _affectedOrders = null;
 }
}
 
[PXOverride]
public void PostPersist(Action base_PostPersist)
{
  _affectedOrders = null;
}

The following example shows how the logic of the void PXGraph.PerformPersist(IPersistPerformer persister) method is overridden. Note that the void PXGraph.PerformPersist(IPersistPerformer persister) base method is not called anywhere in this code because your goal is to take full control of the persisting process.

protected override void PerformPersist(IPersistPerformer persister)
{
   persister.Insert(APPayment_DocType_RefNbr.Cache);
   persister.Update(APPayment_DocType_RefNbr.Cache);
   persister.Update(APDocument.Cache);
   persister.Update(APTran_TranType_RefNbr.Cache);
   persister.Update(APPaymentChargeTran_DocType_RefNbr.Cache);
   persister.Insert(APTaxTran_TranType_RefNbr.Cache);
   persister.Update(APTaxTran_TranType_RefNbr.Cache);
   persister.Insert(SVATConversionHistory.Cache);
   persister.Update(SVATConversionHistory.Cache);
   persister.Insert(APAdjust_AdjgDocType_RefNbr_VendorID.Cache);
   persister.Update(APAdjust_AdjgDocType_RefNbr_VendorID.Cache);
   persister.Delete(APAdjust_AdjgDocType_RefNbr_VendorID.Cache);
   persister.Insert<APHist>();
   persister.Insert<CuryAPHist>();
   persister.Insert<APTranPost>();
   persister.Insert(AP1099Year_Select.Cache);
   persister.Insert(AP1099History_Select.Cache);
   persister.Update(CurrencyInfo_CuryInfoID.Cache);
   persister.Insert<CADailySummary>();
   persister.Insert<PMCommitment>();
   persister.Update<PMCommitment>();
   persister.Delete<PMCommitment>();
   persister.Insert<PMHistoryAccum>();
   persister.Insert<PMBudgetAccum>();
   persister.Insert<PMForecastHistoryAccum>();
   persister.Update<APTax>();
}

Using the void PXGraph.PostPersist() Method

The following code example shows how you can use the void PXGraph.PostPersist() method in a graph when you need to perform some operations after the persist operation.

protected override void PostPersist()
{
 base.PostPersist();
 this.Quotes.Cache.Clear();
 this.Quotes.View.Clear();
 this.Quotes.Cache.ClearQueryCache();
 this.Quotes.View.RequestRefresh();
}