Tech Tip: Calling a Date Dialog From a Method
Collecting date/time input from the user on a form is as simple as adding a Date field to your Aras form. But what if you need to query the user for input during the execution of method code? The Call Date Dialog project on the Aras Labs GitHub page&...0Views0likes0CommentsAras Best Practices: Server-side Code Part 2
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 gist.github.com/.../7a241272b9370923c9f9874e0ff69b9d 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" <Message> <event name="pagemax" value="1"/> <event name="itemmax" value="248"/> <event name="items_with_no_access_count" value="0"/> </Message> 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" gist.github.com/.../acd2a45cf8c103fa85644592eaf38088 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. Conclusion 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.0Views0likes0CommentsAras Best Practices: Server-side Code Part 3
In our previous blog posts on best practices (found here and here), we covered multiple ways to improve the performance of your code by reducing the number of calls to and from the database. We are going to take a bit of deviation away from improving performance in this post and instead focus on another key area of development: maintenance. When writing maintainable code, there are some different goals that we want to achieve. Reduce the number of custom methods in your database. Reduce the size of the custom methods in your database. Make it easy to update the code that you do need to write. Use the Innovator API Aras Innovator ships with a few standard libraries that are accessible from any server-side Method. These libraries are already tested by the Aras QA department, and they very rarely change between the different versions of Innovator. Especially for server-side code, it's not uncommon for Methods originally written in Aras Innovator 9.4 to still work exactly as expected in the currently latest version of 12.0. Apart from the added peace of mind of knowing that your code can be easily ported to a newer version, there's an even better reason to use the Innovator API wherever you can. It's already written! The best code is no code after all, so if we can save the time of needing to write our own functionality, we should. You can take a look at the Innovator API and the objects and functions within it by logging into your instance as an admin and selecting Admin > API Reference (.NET). Use Shorthand Functions The IOM at its core is just a wrapper for writing AML queries, and if you have any experience with writing AML queries manually, you know that you tend to use certain properties and attributes more than others. Our development team also knows this and thus they've added a few useful shorthand functions to accomplish specific tasks with a smaller amount of code. Attribute Shorthands One of the simplest examples of these shorthand functions that we can look at are the functions that cover getting and setting attributes. As you may know, you can set and get any attribute from a request by using the setAttribute and getAttribute functions respectively. However, for some of the most common attributes you will use like type, action, and id, you can use shorthand functions unique to each of those attributes like getType, getAction, and getID. You can see how to use these functions in code as well as their comparison to the standard way in the example below. gist.github.com/.../370a586fc52b486506449f9d3f8feab2 Each use of these shorthand functions will only save a few characters each time, but in the scope of all of your methods, the amount of code saved will add up quite a bit. Using these shorthand functions has an added benefit of throwing an error at compilation time if you happen to misspell one of the attributes since the name is directly in the method. If you misspell one of the attributes that you pass in to the getAttribute or setAttribute functions, your code will instead run and fail, and it may take longer to diagnose what the issue is. Item Shorthands There are also shorthand functions for appending items to a query. Most commonly you might want to do this when you're trying to get both a parent item and some relationship structure underneath it. You can see some examples of these Item shorthand functions compared to their longer-form counterparts below. gist.github.com/.../38a5e8413c504b2817e2ddf745e11267 Avoid Hardcoding If you've developed software outside of Aras Innovator, you may have heard the term "magic number" before. A magic number is some integer value that appears directly in your source code, usually multiple times. This is considered bad practice because if the logic ever needs to change, you will need to update that value at every instance it is being used. A better practice would be to define a named variable to store the value instead of using it directly. Not only does this mean you can update the logic by changing just one section of your code, but giving the variable an appropriate name also helps the readability of your code. Within Innovator, you should also avoid hardcoding values as much as possible. When we write custom methods, they often times start development to solve a problem for a particular ItemType. Because of this, we may hard-code the name of that ItemType into our logic so that our method works only for the specific use case we were trying to solve. With just a little extra work, we can often times expand that method to solve problems people just haven't thought of yet. Let's look at an example where one of our users has complained that someone is claiming Parts and never un-claiming them. They want to be able to run an action on a Part to find out who currently has it claimed, so they can send a friendly reminder to un-claim it. Our first pass at solving this will probably result in a method similar to the one below. gist.github.com/.../3d0b8a653e7895037cf77e721c754d02 This works well enough to make that specific user happy, but we can easily envision a world where the user comes back to report that the same problem is now happening with Documents and CAD. We could write two more custom methods to work for those two ItemTypes respectively, but then we have three methods that are all effectively accomplishing the same thing. If the logic ever needed to be updated, we would need to update it in three different locations. Instead, let's try to rewrite our existing method to remove the hard-coded reference to the Part ItemType inside of our newItem function. We'll define a variable to store this value instead, and while we're at it, we can also look up what ItemType this method is currently running on from this. With that in place, we end up with a generic Method that could run on any ItemType in our database. If the logic ever needed to change, we would only need to update it once. gist.github.com/.../3a2254990ad36109bad0ab779fda3d7a Conclusion When it comes to maintaining code, putting the effort in early will save you an exponential amount of time in the future. Do you already try to use these tips in your day-to-day coding? Are there other practices you or your company use in addition to these? Let us know in the comments below.0Views0likes0Comments