How to call Persist of PXgraph without triggering the code written in that graph
Sometimes there is a need to call the PXGraph.Persist method from a graph extension but without triggering the code written in the base graph itself. I had this issue with using the ARSalesPriceMaint graph, so will show all the examples on that graph extension.
The problem is, it’s not possible to just call it, as it is not reachable from the GraphExtension level.
There was a solution by using reflection. Something like this:
public void Persist(Intercompany.PersistDelegate baseMethod) { //base.Persist(); MethodInfo fooA = typeof(PXGraph).GetMethod("Persist", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { }, null); DynamicMethod baseBasePersist = new DynamicMethod("foo_A", null, new[] { typeof(PXGraph) }, typeof(PXGraph)); ILGenerator il = baseBasePersist.GetILGenerator(); il.Emit(OpCodes.Ldarg, 0); il.EmitCall(OpCodes.Call, fooA, null); il.Emit(OpCodes.Ret); baseBasePersist.Invoke(null, new object[] { Base }); }
The problem with this solution is that first of all, any error messages thrown from the base Persist method will not appear on the screen instead of them only the “Exception has been thrown by the target of an invocation” appears. The second and the bigger issue is – all the caches will remain not cleared. It will cause some unexpected behavior, when the already deleted wrong record won’t allow to save the screen.
Since for the PXGraph.Persist we don't need specific graph logic, instead of calling the PXGraph from ARSalesPriceMaint base graph, we can create a completely empty new custom graph, then call it from our graph extension while passing all the caches and views. Additionally, we can even add some validations to the persist at the graph level.
This is the code example:
internal class ARSalesPriceMaintPersistHelper : PXGraph<ARSalesPriceMaintPersistHelper> { public override void Persist() { MyValidation(); base.Persist(); } protected virtual void MyValidation() { PXTrace.WriteInformation("Overriden Validation is called"); } } public class ext : PXGraphExtension<ARSalesPriceMaint> { public delegate void PersistDelegate(); [PXOverride] public void Persist(PersistDelegate baseMethod) { ARSalesPriceMaintPersistHelper ph = PXGraph.CreateInstance<ARSalesPriceMaintPersistHelper>(); ph.Views = Base.Views; ph.Caches = Base.Caches; ph.Persist(); Base.Cancel.Press(); } }
The Graph was made internal to try to avoid its appearance in different graph selector in Acumatica, but it can also be just public.
Summary
In addressing the challenge of invoking PXGraph.Persist in Acumatica from a graph extension, there is a nuanced solution beyond the initial reflection method. The initial approach, while innovative, led to issues with error messaging and cache management. Solution involves creating a new, custom graph specifically for handling the Persist method. This method ensures functional integrity and enables custom validations, effectively bypassing the limitations of the reflection-based approach. The article concludes with a practical code example, highlighting the new graph's internal designation to restrict its visibility in Acumatica.