3

I have heavy operation that worked properly (but too long):

_terminationHandler.InsertOrUpdateEmployeeTerminationDetails(TerminationFilters.Current, EmployeeTerminationItems, EmployeeTerminations.Current);

In the Graph that defined this way:

public class MPEmployeeTerminationMaint : PXGraph<MPEmployeeTerminationMaint>

That generates data grid content in these 2 tabs (a few records will be generated): enter image description here I was recommended to use PXLongOperation:

      public async virtual void MPEmployeeTermination_TerminationDate_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e)
    {
        PXLongOperation.StartOperation(this, () =>
        {
            _terminationHandler.InsertOrUpdateEmployeeTerminationDetails(TerminationFilters.Current, EmployeeTerminationItems, EmployeeTerminations.Current);
        });
    }

Operation starts: enter image description here However it crashes UI (or something happened) after a while: enter image description here But no exception is thrown. So there is no exception or another hint what happened. If you change a editable property, you receive exception: enter image description here The "trace" Acumatica page is empty.

If I don't send this to the PXLongOperation this problem is resolved:

  PXLongOperation.StartOperation(Guid.NewGuid(), () =>
        {
            _terminationHandler.InsertOrUpdateEmployeeTerminationDetails(TerminationFilters.Current, EmployeeTerminationItems, EmployeeTerminations.Current);
        });

however I don't have then indication to the user that long operation happens (obviously: there is no connection between long operation and UI without this anymore).

What is defined wrongly?

I want to improve user experience and allow him to continue working with the UI when heavy operation happens. If I can achieve this aim in another way - it is also fine. For instance, I can use Guid.NewGuid() instead of this, but then I need to refresh UI manually and moreover the data is not saved.

I will be very grateful to any advice.

Mr.B
  • 3,484
  • 2
  • 26
  • 40
  • 1
    Have you tried removing the async keyword from your event handler? – Gabriel Mar 11 '20 at 11:14
  • Yes, I've tried to remove async, but my page is defined as async <%@ Page Async="true" Because I have one heavy method that runs asynchronously. Does it matter? – Mr.B Mar 11 '20 at 21:15
  • I’m just unsure if this is supported by Acumatica... it’s web forms behind the scenes but highly customized. It’s not something I’ve seen used with Acumatica yet, so that’s the first thing I would have tried to rule out completely – Gabriel Mar 12 '20 at 01:28

2 Answers2

1

By any chance, in your long operation, are you changing key fields of your Current object? By Key fields I mean fields which are marked as IsKey. I have encountered your similar behaviour previously when I tried modifying IsKey values. Also don't assign the Current of your main Data View to a completely different object because that could also result in the same issues.

One other thing, you might want to change how you reference the graph from your long operation. You should not reference this directly inside the method of your long operation because it would not allow Acumatica to execute the code Asynchronously. Ideally you would create a static method. I was speaking to Acumatica recently on this and they suggest the below approach.

   ...
    var graphCopy = this;
    PXLongOperation.StartOperation(this, delegate { 
        //Encapsulating the logic in static method and calling it this
        doMyBusinessLogic(graphCopy); 
    });

}

static void doMyBusinessLogic(MyGraph graph){ 
    //Here VS will throw an exception if references of this graph are used
}       

If you want to update the UI ater the long operation, consider using PXCustomInfo.

To troubleshoot your issue would be to start commenting out code from your Long Operation and then re-test. This will help you identify which code is causing the problem.

Finally, one other suggestion is to try calling Save.PressButton(adapter) before your long operation. This is especially required if you are starting the long operation on a new record before saving.

 [PXUIField(DisplayName = "Start", MapViewRights = PXCacheRights.Update,
  MapEnableRights = PXCacheRights.Update)]
 [PXProcessButton]
 protected virtual IEnumerable Start(PXAdapter adapter)
 {
     Save.PressButton(adapter); 
     //...
  }
Joseph Caruana
  • 2,241
  • 3
  • 31
  • 48
  • 1
    Thank you for sharing your knowledge. This solution doesn't resolve the problem, however, I found what is the reason of the problem. I will post it. – Mr.B Mar 12 '20 at 02:57
1

I found the reason of the problem. I don't understand why it happens and this knowledge doesn't resolve my problem, however, it is not a mystery anymore: when we call

 PXLongOperation.StartOperation(this, () =>
    {
        _terminationHandler.InsertOrUpdateEmployeeTerminationDetails(TerminationFilters.Current, EmployeeTerminationItems, EmployeeTerminations.Current);
    });

it actually create the instance of graph again and all properties that were previously set up, are nulls again. Everything needs to be set up again. This method returns empty enumerable. However, I still don't understand why the graph is empty and why there is no exception thrown. So I believe the solution is to debug the code thoroughly and make sure that all properties, views etc have expected values. In my case EmployeeTerminations.Current is null. it doesn't throw exception because I have condition that returns

return Enumerable.Empty<MPEmployeeTerminationItem>().ToList()

when currentEmployeeTermination is null, but when your view override is empty collection your Current is null. and as a result all "bindings" in your UI will fail. Hope it will help to somebody.

Mr.B
  • 3,484
  • 2
  • 26
  • 40