0
votes

I have a graph used by a screen that I'm accessing via a webservice endpoint, e.g.

http://myserver/entity/MyEndpoints/17.200.001/MyEndpoint

In the graph I'm defining

    public PXSelectReadonly<MyDAC> Items;

and then a delegate to serve the Items

    protected virtual IEnumerable items()

When I try to access the endpoint, I get an error:

    "There is a BqlDelegate in view Items"

and an exception of type PX.Api.ContractBased.OptimizedExport.CannotOptimizeException

I can't find anything on this anywhere, so I'm a bit stumped.

The reason I didn't use generic inquiries for this, is due to the logic in the delegate, which is a bit more intricate than GIs are capable of.

Any ideas?

2
Are you trying to do a Get() or GetList() call on that endpoint? - Gabriel
Hi Gabriel, for testing purposes I'mm using Postman to do a GET request on the service endpoint - Birgir Kristmannsson

2 Answers

0
votes

I used Jetbrains Dotpeek to dig into Acumatica's source code.

Found an answer to my own question, which at least allows me to use the graph as is

Adding the following attribute declaration to the graph class allows the delegate to be used

[NonOptimizable(IgnoreOptimizationBehavior = true)]

b

0
votes

Acumatica tries to optimize the API call by "translating" it to a single SQL query. It does it by looking at your endpoint definition, the fields that you want returned, and the actual BQL queries behind it. If you have a delegate, it can't and won't do it, unless you tell the system that it is "safe" to do so.

In the past, Acumatica would end up silently executing the delegates, leading to very poor performance when doing a GetList() on a large dataset. A good example is the Sales Order screen; there's a delegate behind the Transactions view (SOLine). Without this optimization, returning all orders and order lines in a single GetList() call would force the system to invoke the delegate for every single order, resulting in hundreds or even thousands of SQL queries!

In this case however, the delegate is only used to cache some data related to the item cost, so the Transactions view delegate was marked with the following attribute:

[Api.Export.PXOptimizationBehavior(IgnoreBqlDelegate = true)]
protected virtual IEnumerable transactions()

That tells the system that it is safe to ignore the delegate, and optimize the Transactions view like any other PXSelect. If the delegates must be invoked for your data to be returned properly, then you must use another attribute, this time on the graph itself:

[Api.Export.NonOptimizable(IgnoreOptimizationBehavior = true)]
public class SomeGraph : PXGraph<SomeGraph>

No optimization will be done by the system and system will invoke the delegate at all times. This will more than likely result in slower than expected response, especially when the delegate is not the primary view. There's another variant of this attribute where you can identify specific fields that can't be optimized; this will result in optimization being enabled unless you include these fields as part of your endpoint:

[Api.Export.NonOptimizable(new Type[] { typeof(ARPayment.adjDate), typeof(ARPayment.curyApplAmt) })]

In the past, Acumatica silently reverted to non-optimized behaviour, but this was very problematic because small changes to a graph would wreak havoc on API performance, and problems would get detected too late.

Note that these attributes are undocumented, and are used internally only for now. My advice is to avoid having to use them as much as possible, and stick to simple graphs and selects without delegates if possible...