Creating the setup tables

Setup tables are normally created first as they are used on the main and transactional tables. Before a table is created, we must know which extended data types and enumerated types will be used or created.

The structure follows a common pattern, and you are welcome to create the tables based on the definitions described in the following section, using the detailed steps to check against. The tables and types created in the following section will be used in the upcoming chapters.

Creating the vehicle group table

The vehicle group table is a Group table, which is in common use in AX, and most main tables have a group field to assist in reporting, filtering, and other requirements. The definition is given here:

Table

Label

Table group

 

ConFMSVehicleGroup

Vehicle groups

Group

 

Field name

Type

Size

EDT

VehicleGroupId

String

10

ConFMSVehicleGroupId

Description

String

60

Description

Note

Although it would suffice in terms of naming conventions to use Type and Group, this would be bad practice as we shouldn't use SQL or AX keywords as field names. Examples of such keywords include use, select, order, group, and so on.

The table is prefixed with ConFMS so that we can easily see the objects that are specific to this solution. For smaller ad hoc changes, it may be sufficient to add the organization prefix. The fields are not prefixed as they are in "our" object.

Creating extended data types

The VehicleGroupId field is a standard field type, and will almost always be a string of length 10. It will have its own EDT, but will extend the standard group EDT of SysGroup. This is an EDT that most group EDTs extend, such as the customer, item, and vendor group EDTs.

Description is a standard EDT, and we will use this only when we create the table. There are several EDTs that we will see reused on many tables, such as Name and Description.

To create the ConFMSVehicleGroupId EDT, follow these steps from within the MorphX IDE:

  1. Open the ConFleetManagementSystem project, which we created in the last chapter.
  2. Expand the Data Dictionary node and right-click on Extended Data Types, navigating to New | String, as shown in the following screenshot:
    Creating extended data types
  3. Rename the new EDT from Type1 to ConFMSVehicleGroupId. You can use the option Rename from the context / right-click menu, but F2 is quicker.
  4. Open the properties for the new type: press Alt + Enter or choose Properties from the context/right-click menu.
  5. In the Label property, enter Vehicle group and create a label.
  6. Enter the HelpText in the same way. This is not mandatory but should be filled in because it helps the user. It appears as a popup when you move the mouse over the field linked to this EDT.
  7. For now, we will skip to the Extends property and return to the other properties later. In the Extends property, enter SysGroup. Note that as soon as you enter SysGr, AX will enter the rest for you.

    Note

    The Extends property lets us specify which EDT we will inherit properties from. We can change all of these properties except Size and Adjustment (to ensure referential integrity of all child EDTs).

  8. We should have three properties highlighted in bold, as we have changed from the default value, as shown in the following screenshot:
    Creating extended data types
  9. If there is a red vertical line next to our new EDT, it means it is not saved in the model store database. Press save all in the project window.

The EDT is not yet complete. We need to create the EDT's primary table, the vehicle group table.

Note

There is often an element of going back to finish an element's definition. In this case, we need the EDT to create the table, but we also need the table to complete the EDT.

Creating the table

The group tables are a common table type, and requires at least two fields, a group field and a description field.

There are some table properties that we will need to complete before we move on to creating the two methods. To create the table definition, follow these steps:

  1. Using keyboard shortcuts where possible, create a new table called ConFMSVehicleGroup under the Tables node in your project.
  2. Set the Label property Vehicle groups, and create a label as we did earlier.
  3. Set HelpText to further describe the table for the user. This is part of best practice checks performed by the compiler.
  4. Change the TableGroup property's value to Group.
  5. Although not mandatory, it is a good idea to turn on the ModifiedDateTime, ModifiedBy, CreatedDateTime, and CreatedBy tracking fields.

    Note

    The TableGroup property tells AX what type of data the table will hold and also allows us to manage tables based on this. For example, we can choose to export data for all tables of the type Group.

Adding fields to the table

Next, we need to add our two fields, which can be done by right-clicking on the Fields node, but they are much quicker to create by dragging and dropping. To do this, follow these steps:

  1. On the table ConFMSVehicleGroup, drag the ConFMSVehicleGroupId EDT onto top of the Fields node, and rename this to VehicleGroupId
  2. This will be the primary key, so set the Mandatory property to Yes, set AllowEdit to No, and leave AllowEditOnCreate as Yes.
  3. This creates a field of the same name. Rename this to VehicleGroupId.
  4. Open the field's properties, set the Mandatory property to Yes, set AllowEdit to No, and leave AllowEditOnCreate as Yes.

    Note

    Since we will leave AllowEditOnCreate as Yes, we can enter the ID but not change it afterwards; this helps enforce referential integrity. It can still be changed using the Rename primary key function, but this should still be used with care after consultation with a developer or technical consultant.

  5. Open a new AOT window (Ctrl + D) and position it side-by-side with your project window.
  6. Expand the Data Dictionary node and the Extended Data Types node so as to navigate to the Description EDT.

    Tip

    Remember that you can start typing to search, which causes AX to auto-search for the first matching node on the same level.

  7. Drag Description onto your table's fields list.
  8. Press the save all icon in the project window to ensure that your changes are saved.
  9. Go back to the table's properties. Set the TitleField1 property to VehicleGroupId and TitleField2 to Description. AX can show these fields on forms that have this table as a data source.

Creating field groups

To aid the user interface design, we can place our fields in groups. This helps us provide a consistent interface for our users and also provides better and centralized control over the UI.

We only need one field group, as there is only a grid view of two fields. We will call this Overview. The following steps will create the field group:

  1. Right-click on the Field Groups node and choose New Group.
  2. Rename the group to Overview.
  3. Open the properties and change Label to Overview.
  4. Open the Label editor (press Ctrl and the spacebar) and wait a few seconds, as the first set of results is for specific contexts.
  5. Select the first Overview label with no description and press Paste label.
  6. Drag both the fields from the field list into the group. You can reorder them so that VehicleGroupId is first, using either the mouse or Alt and the up arrow key.

There are two other key field groups, AutoLookup and AutoReport. The AutoLookup field group governs the fields that appear when the system constructs a drop-down list against the table. The AutoReport field group governs the fields that appear should the user choose to create a quick report for the table. For this table, add all the fields to these two groups.

Creating indexes

The next part is to set up indexes. We set up indexes both for performance and to enforce unique constraints. There is another more fundamental reason. You may have noticed that the primary and clustered indexes were SurrogateKey. This is the default index, based on the record ID (RecId). Should we add a primary key relation, it will be based on that index and therefore on the RecId field. A record ID foreign key is of little use to us, as we intend the vehicle group ID to be placed on our vehicle table for grouping and reporting purposes.

So, we need to create a unique index based on the VehicleGroupId field, and tell the table to use this as its primary key. To create the primary index, follow these steps:

  1. On the Indexes node of your table, right-click and choose New Index.
  2. Rename the index from Index1 to VehGroupIdx.
  3. Drag the VehicleGroupId field onto VehGroupIdx to add this field to the index.
  4. Go to the properties of the VehGroupIdx index and change the AllowDuplicates property to No and the AlternateKey property to Yes.

    Note

    Unless both of these are set, we won't be able to set the index as the table's primary key.

  5. Press the save all icon in the project window. This causes the changes to be saved and the index to be created within SQL Server.
  6. Go to the properties of the ConFMSVehicleGroup table.
  7. Change PrimaryIndex and ClusteredIndex to VehGroupIdx.

Adding the find and exist methods

The final step before we hook up the user interface is to add a find and an exists method. These aren't used by the system, but it is a convention to create these methods on the tables we create. As the table's authors, we understand how to find records on this table and this saves time later as we avoid writing select statements to find the record.

These methods follow the same pattern for all tables we create, and are based on the primary key field, or fields. In our case, we have the VehicleGroupId key field, which is based on the ConFMSVehicleGroupId EDT (type).

The find method allows us to locate a record based (usually) on its primary key, and choose whether or not it should be selected for an update (locked). The method is a static method, which means we don't need to instantiate the table before calling it.

First, to create the find method, right-click on the Methods node and choose New Method. This will show a method template:

private void method1()
{
}

Methods marked as private are only visible for calls within this table. Our method is designed to be called from other objects and these methods are also declared as static, which is done as follows:

public static void method1()
{
}

The next part is the type of object the method returns. The method template assumes to be void. We want to return a record of the type ConFMSVehicleGroup, so replace void with the table name, but watch what happens as you type.

Replace void with the table name, but watch what happens as you type:

Adding the find and exist methods

Use the arrow keys to choose the appropriate type from the pop-up list. In this case, it is highlighted, so just press Enter.

Rename the method to find, and specify the parameters that the method accepts: the primary key field and whether or not the record should be selected for update.

These are specified as follows:

public static ConFMSVehicleGroup find(
                               ConFMSVehicleGroupId _groupId, 
                               boolean _forUpdate = false)
{
}

Note

The underscore is the naming convention for parameters, and the = false assignment means that the parameter is optional and defaults to false.

We now have a vehicle group and know whether we should lock the record. We can now write the method's content.

The pattern for this method is similar each time we use it, and is done by:

  • Declaring the table
  • Using the _forUpdate parameter to mark the table as for update
  • Writing a select statement to select the record
  • Returning the record, even if not found

To save making a needless select call, we can also make the call only if the vehicle group is not empty. The final code will be like this:

public static ConFMSVehicleGroup find(ConFMSVehicleGroupId _groupId, boolean _forUpdate = false)
{
    ConFMSVehicleGroup vehicleGroup;
    
    vehicleGroup.selectForUpdate(_forUpdate);
    if(_groupId != "")   
    {
        select firstonly vehicleGroup 
            where vehicleGroup.VehicleGroupId == _groupId;
    }
    return vehicleGroup;    
}

Note

The firstonly keyword tells SQL to select only the first record it finds, which is the same as TOP 1 in Transact-SQL. It doesn't make a great deal of difference here because we are searching the primary key. Nevertheless, if we intend to fetch only the first record, it gives a performance boost.

The exists method is similar but returns true or false, depending on whether the record was found. The way to determine whether a record was found is to check whether the record ID is zero or not.

To improve performance, we will select only the RecId column from the table. The method should look like this:

public static boolean exist(ConFMSVehicleGroupId _groupId)
{
    ConFMSVehicleGroup vehicleGroup;
    if(_groupId != "")   
{
     select RecId 
         from vehicleGroup 
         where vehicleGroup.VehicleGroupId == _groupId;
}
    return (vehicleGroup.RecId != 0);        
}

Close the code editor and press Save All.

Tip

To create a new method while in the code editor, press Ctrl + N.

Aside from some user interface elements, our table is complete. You can browse the data in it using the table browser by choosing Open from the table's context menu on the table.

You will notice some system-generated fields here, which are as follows:

Field

Description

RecId

A system-generated and system-maintained unique record identifier.

RecVersion

This is used as part of the optimistic concurrency mechanism in order to determine whether the record we have is still current.

DataAreaId

For tables that store data per company, this contains the company ID and is automatically filtered to the current company.

Partition

This is the current partition, and is filtered at the kernel level.

Completing the primary key EDT

There is one key step remaining to complete the ConFMSVehicleGroupId EDT, that is, to tell the system how it relates to the vehicle group table.

Whenever we add an EDT that is also the primary key of a table, we need to give AX some information; this pays dividends later. To complete this setup, follow these steps:

  1. Open the properties of the ConFMSVehicleGroupId EDT.
  2. In the ReferenceTable property, enter ConFMSVehicleGroup.

    Note

    As soon as you type ConFM, AX will complete the rest for you.

  3. Expand the ConFMSVehicleGroup node and right-click on Table references.
  4. Go to New | Table reference from the context menu.
  5. In the property sheet, AX has already populated the Table property with ConFMSVehicleGroup. Set the RelatedField property to VehiceGroupId.

AX will now understand that the ConFMSVehicleGroup EDT should be a foreign key to this table, and also will offer a drop-down list of vehicle groups.

More on indexes

A table index is a structure designed to make finding a specific record as fast as possible. The index is an ordered collection of keys and pointers to the actual records. Finding a record matching a given key involves going to the appropriate location in the index where that key is stored. Then you have to follow the pointer to the location of the actual record and the rest of the data. This, of course, requires two operations, an index seek and a lookup to get the actual data.

When we search for a record, SQL Server is able to determine the best index, or indexes, to use for that particular query. If we realize that we often require the same set of fields from a specific query, we can create an index that contains the keys we wish to search on and the fields we wish to fetch. This improves performance considerably, as SQL will use that index and can then simply return the values that already exist in the index.

We can improve this further by marking the fields we simply wish to return as IncludedColumn (a property of the fields in an AX index). So in our case, we may wish to select the description from the vehicle table where the vehicle group is Artic. Therefore, a solution can be to add the Description field to our VehGroupIdx index and mark it as IncludedColumn. However, there is a better solution in this case, which is to use clustered indexes.

A clustered index is similar to this, but the clustered index will contain the entire record, avoiding a lookup in the data for any field in the table. Clustered indexes are sorted by their keys; since the index contains the entire record, it can add a significant load to SQL Server if records are inserted, as opposed to being appended at the end of the table.

For setup tables where the number of records is small and changes infrequently, this isn't a problem and the read benefit far outweighs any drawback. For transactional tables, we must be careful. We should always have a clustered index, but the key must be sequential and the records must be added at the end of the table. In any case, we must have a clustered index.

An example of this is the sales order table, which has a clustered index based on SalesId. This is a great choice as we will often use this key to locate a sales order record, and the field is also controlled by a number sequence; records should always be appended at the end. However, should we change the number sequence so that records are inserted "mid-table", we will experience a delay in inserting records, adding an unnecessary load to SQL Server.

Creating the vehicle service schedule table

The next table will hold the various service schedules for the vehicles we have. This will be a simple, linear schedule of the distance or elapsed days. We could simply have this information held against the vehicle directly, but since this type of information will be the same for a make and model of vehicle, it is better to hold the schedule as a related record. In our solution, we will select the service schedule for each vehicle.

This is a common design decision, do we assign this directly to the entity, via a rule set, or by some other criteria? Perhaps the service schedule should be implied by other properties, for example, make and model year. This could be equally restrictive, so another option can be to limit the choices to a valid option when creating the vehicle.

The table we will create is as follows:

Table

Label

Table group

 

ConFMSVehicleSchedule

Service schedule

Group

 

Field name

Type

Size

EDT

VehicleScheduleId

String

10

ConFMSVehicleSchedId

Description

String

60

Description

Distance

Integer

 

ConFMSDistance

Days

Integer

 

Days

This time, we will just list the steps required:

  1. Create the ConFMSVehicleSchedId EDT as a String type, extending SysGroup with Label as Service schedule.

    Note

    Remember to create and paste the label as before.

  2. Create the ConFMSDistance EDT as an Integer type, and set Label to Distance.

    Tip

    Since distance will never be negative, we can set the AllowNegative property to No; this helps reduce data entry errors. It also reinforces the power of EDTs. We can control these properties from one entity, wherever they are used.

  3. Create the ConFMSVehicleSchedule table:
    1. Set Label to Service schedules.
    2. Add appropriate HelpText.
    3. Set TableGroup to Group.
    4. Set the required tracking fields.
    5. dd the following fields from EDTs, in the given order: ConFMSVehicleSchedId, Description, ConFMSDistance, and Days.

    Note

    As each field is created, it will be the first field in the listing. However, you will see that when the table refreshes (or if you restart your client), the fields will be ordered differently. They are ordered by their ID.

  4. Remove the prefix from the field names as per the earlier table definition.

    Tip

    Remember to make the primary key field VehicleScheduleId Mandatory and not AllowEdit.

  5. Set the title field properties, VehicleScheduleId and Description.
  6. Create the primary index, VehicleScheduleIdx. Add the VehicleScheduleId field.
  7. Set AllowDuplicates to No and AlternateKey to Yes.
  8. Set the table's primary and clustered indexes to the new index.
  9. Create a field group for Overview (with a label as before) with the VehicleScheduleId and Description fields.
  10. Create a field group called Schedule and create a label and add the Distance and Days fields.
  11. Create the find and exist methods as per these code samples:
    public static ConFMSVehicleSchedule find(
                                ConFMSVehicleSchedId _schedId, 
                                boolean _forUpdate = false)
    {
        ConFMSVehicleSchedule vehSched;
    
        vehSched.selectForUpdate(_forUpdate);
        if(_schedId != "")
        {
            select vehSched 
                where vehSched.VehicleScheduleId == _schedId;
        }
        return vehSched;
    }
    
    public static boolean exist(ConFMSVehicleSchedId _schedId)
    {
        ConFMSVehicleSchedule vehSched;
        if(_schedId != "")
        {
            select RecId 
                from vehSched 
                where vehSched.VehicleScheduleId == _schedId;
        }
        return (vehSched.RecId != 0);
    }
  12. Press the Save All button, and we're done!

After some time, creating tables like this becomes almost muscle memory, and we can do it without thinking. Moreover, if you learn the keyboard shortcuts, it becomes very quick.

We can create code snippets for the find and exists methods; code snippets are covered in Appendix C, Code Editor Scripts.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.216.27.251