In our previous blog post on server-side best practices, we shared some tips on how to improve the performance of your custom functionality by focusing on two key goals.
- Reducing the number of queries sent to the database
- Reducing the amount of data returned from the server
In this blog post, we'll cover a few more tips to help you achieve these goals and keep your Aras Innovator instance running as smoothly as possible.
Use doGetItem="0" with Add and Edit Requests
When you're sending a request to the database that's using the "add", "edit", or "update" actions, consider if you're actually going to use the resulting item later in your code. If the item is not going to be used, you can add a handy attribute called doGetItem to your request to greatly reduce the amount of data you'll get back from the server. If you set the value of this attribute to "0", only the ID of the newly created or modified item will be returned.
Example C# Code Using doGetItem
Response With doGetItem="0"
<Item type="Part" id="3976B16DF29044CFAE02E2915B2AB05B"/>
You can compare this response we get when using doGetItem="0" with the normal response below.
Response With doGetItem="1"
<Item type="Part" typeId="4F1AC04A2B484F3ABA4E20DB63808A88" id="D5CBA439ED61491F9667840B3A255866"> <config_id keyed_name="New Part 3" type="Part">D5CBA439ED61491F9667840B3A255866</config_id> <created_by_id keyed_name="Innovator Admin" type="User">30B991F927274FA3829655F50C99472E</created_by_id> <created_on>2020-12-16T15:57:45</created_on> <current_state name="Preliminary" keyed_name="Preliminary" type="Life Cycle State">72A2322564FE4193933CFB5339487A06</current_state> <generation>1</generation> <has_change_pending>0</has_change_pending> <id keyed_name="New Part 3" type="Part">D5CBA439ED61491F9667840B3A255866</id> <is_current>1</is_current> <is_released>0</is_released> <keyed_name>New Part 3</keyed_name> <major_rev>A</major_rev> <make_buy>Make</make_buy> <modified_by_id keyed_name="Innovator Admin" type="User">30B991F927274FA3829655F50C99472E</modified_by_id> <modified_on>2020-12-16T15:57:48</modified_on> <new_version>0</new_version> <not_lockable>0</not_lockable> <permission_id keyed_name="New Part" type="Permission" origPermission="5C07EB829D4241F6BB884952960FAF58">5C07EB829D4241F6BB884952960FAF58</permission_id> <state>Preliminary</state> <unit>EA</unit> <item_number>New Part 3</item_number> <itemtype>4F1AC04A2B484F3ABA4E20DB63808A88</itemtype> </Item>
Use returnMode="countOnly" to Get the Number of Items
Occasionally, you will find yourself in a situation where you need only the number of items of a specific type. While you could do a blanket get and then retrieve the count using Item.getItemCount(), this will also return a lot of excess item data that will slow down your method unnecessarily. If just the number of items is needed, you can use the returnMode attribute with a value of countOnly to have the server return only information about the count with no additional item information.
Response with returnMode="countOnly"
<event name="pagemax" value="1"/>
<event name="itemmax" value="248"/>
<event name="items_with_no_access_count" value="0"/>
The pagemax is the total number of pages that will be required to display the items based on the page and pagesize attributes of the original query. When we generated the response above, we did not include those, so the pagemax is just set to 1. The itemmax is what we're actually looking for here and contains the total number of items in the database that match the criteria of your query.
You'll notice that this result looks a lot different than the usual Item AML we'd expect to get back from a typical get query. Because of this, the code for retrieving the count values will be a little different than the standard getProperty function. You can see an example of how to use this attribute and how to retrieve the count in the sample code below.
Example C# Code Using returnMode="countOnly"
Avoid Making Database Calls Within a Loop
This tip was briefly touched upon in the previous best practices blog, but we'll explicitly call it out again here. Functions like Item.apply, Innovator.getItemById, and Innovator.getItemByKeyedName all make requests to the server, and they should never be used within a loop. Calls to the server can drastically affect performance, especially in environments with a high amount of latency. As much as you can, you should combine calls to the database together so that you ping the server as infrequently as possible.
If you notice that a particular action is taking a much longer time than you'd expect, check your code to make sure there isn't some unintentional server call happening multiple times. Sometimes a helper function will be written so that it makes a call to the database, and then that helper function will unwittingly be used inside of a loop.
Avoid Using applySQL
The last tip we'll mention is that you should avoid using Innovator.applySQL in your custom functionality. Running SQL directly may seem appealing for the same reason that we suggest you avoid it; it bypasses the Aras permission model. Bypassing the permissions checks will tend to have some performance improvement, but the tradeoff is that you introduce a security risk which is a far greater concern. Applying SQL directly is sometimes suggested as a quick way to make one-time data fixes, but running SQL should never be a regular part of your business operations.
These tips should help you keep the back and forth between the client and the server as short and sweet as possible. Look through some of your custom methods and see if you can apply any of these tips to make the performance even better. Keep an eye out for our next best practices blog post that will cover tips how to improve the maintainability of your custom methods.