Reader small image

You're reading from  Programming Microsoft Dynamics 365 Business Central - Sixth Edition

Product typeBook
Published inApr 2019
PublisherPackt
ISBN-139781789137798
Edition6th Edition
Right arrow
Authors (3):
Marije Brummel
Marije Brummel
author image
Marije Brummel

Author, programmer, consultant, project manager, presenter, evangelist, sales person, and a trainer. It's next to impossible to find someone as experienced as Marije Brummel in the Business Central community. Marije received the Microsoft MVP and the NAVUG All-Star awards among several others. She has chaired the Dynamics Credentialing committee and has authored official Microsoft Exam materials. She's the go-to girl for performance troubleshooting and upgrade challenges. One of her biggest achievements was introducing Design Patterns into the Business Central community. Her books, blog articles, and YouTube videos have influenced almost everyone involved with Business Central. She enjoys the outdoors with her dog and loves spending time with her family.
Read more about Marije Brummel

David Studebaker
David Studebaker
author image
David Studebaker

David Studebaker has been designing and developing software since 1962 as a developer, consultant, manager, and business owner. In 1967, David coauthored the first general-purpose SPOOL system, an AT&T / IBM joint project. He has been a founding partner in several firms, most recently Studebaker Technology and Liberty Grove Software. David's publications include a decade of technical reviews for ACM Computing Reviews and a number of articles on shop floor data collection. David originated the Packt series of books on programming Dynamics Business Central (aka Dynamics NAV). He has a BS in mechanical engineering from Purdue University and an MBA from the University of Chicago. He is a life member of the Association for Computing Machinery.
Read more about David Studebaker

Christopher D. Studebaker
Christopher D. Studebaker
author image
Christopher D. Studebaker

Chris Studebaker was a certified environmental consultant working with manufacturing facilities to meet national and state regulations before he started working with Navision in 1999. After working on regulatory reporting, data analysis, project management, and subcontractor oversight, Chris has used those skills to sell, develop, and implement NAV for the past 20 years. He has specialized in retail, manufacturing, job shop, and distribution implementations, mostly in high-user-count, high-data-volume applications. Chris acts in a consulting and training role for customers and for peer NAV professionals. He has a Bachelor of Science degree from Northern Illinois University and has done graduate work at Denmark Technical University.
Read more about Christopher D. Studebaker

View More author details
Right arrow
Introduction to AL
"Programs must be written for people to read, and only incidentally for machines to execute."
– Harold Abelson and Julie Sussman
"The details are not the details. They make the design."
– Charles Eames

So far, we have reviewed the basic objects of Business Central, such as tables, data fields, pages, queries, and reports. For each of these, we reviewed triggers in various areas, the purpose of which are to be containers for AL code. When triggers are fired (invoked), the AL code within is executed.

In this chapter, you'll start learning the AL programming language, though many of the things we will cover you should already know about from your experience programming in other languages. Some of the basic AL syntax and procedure definitions can be found in the Business Central help, as well as in Microsoft Docs for Microsoft...

Understanding Visual Studio Code

With a few exceptions, all of the development for Business Central applications takes place within Visual Studio Code. Exceptions include the use of Microsoft Word (or Microsoft SQL Server) for reporting, as we saw in Chapter 5, Queries and Reports, plus the work we may do in the JavaScript language to create compatible add-ins. While it is possible, development using a text editor is only appropriate for special cases, such as making modifications to existing objects, which is done by an advanced developer.

As an Integrated Development Environment (IDE), Visual Studio Code provides us with a rich set of tools for our AL development work. While Visual Studio Code is not as fully featured as Microsoft's Visual Studio, it is intended to be a cross-platform, modern development toolkit. Most importantly, Visual Studio Code is the most popular IDE and chances are you are already familiar with it.

Explorer

All Business Central object development work starts from within Visual Studio Code in the EXPLORER. After opening a project folder, you should be able to see the following screen:

The type of object that we'll be working on is chosen by the object definition, which we can view by clicking on one of the files in the menus, as shown in the following screenshot:

It is considered a best practice to apply logical naming to your files so that you can see which object type and ID is used without having to open each individual file.

Starting a new object

When we select New File from the File menu, we get a blank file to create a new object, as shown in the following screenshot:

The fastest way to define a skeleton object is to use snippets. To enable the snippets, we must first save our new file using the .al file extension.

This forces us to think about file naming before defining the object, but we can always rename the file after the object's declaration is done.

To start using snippets after saving the file, we simply type the letter t and wait for IntelliSense to show the list of available snippets:

Once we select a snippet, the cursor automatically takes us to the first variable we have to populate. We can use the Tab key to move through the fields one by one:

Object designer navigation

In many places in the various designers within Visual Studio Code, there are standard keyboard shortcuts available. Some of these are as follows:

  • Ctrl + N to create a new empty file
  • Ctrl + O to open an existing file
  • Ctrl + spacebar to access AL IntelliSense, which shows us what we can do for the object that we are working on
  • F5 to publish the project
  • Ctrl + Shift + B to do an on-the-fly build (very useful for error checking as we go)
  • Ctrl + to comment or uncomment code and properties
  • Ctrl X, Ctrl C, and Ctrl + V in normal Windows mode for deletion (or cut), copy, and paste, respectively
We can cut, copy, and paste AL code—even procedures—relatively freely within an object, from object to object, or to a text-friendly tool (for example, Word or Excel) much as if we were using a text editor. The source and target objects don't need to be of the same type.

The easiest way to copy a complete object is...

Some AL naming conventions

In the previous chapters, we discussed naming conventions for tables, pages, and reports. In general, the naming guidelines for Business Central objects and AL encourage consistency, common sense, and readability. Use meaningful names. These make the system more intuitive to the users and more self-documenting.

When we name variables, we must try to keep the names as self-documenting as possible. We should differentiate between similar, but different, variable meanings, such as Cost (cost from the vendor) and Amount (selling price to the customer). Embedded spaces, periods, or other special characters should be avoided (even though we find some violations of this in the base product). If we want to use special characters for the benefit of the user, we should put them in the caption, not in the name. If possible, we will stick to letters and numbers in our variable names. We should always avoid Hungarian naming styles (see https://docs.microsoft.com/en-us/previous...

Variables

As we've gone through examples showing various aspects of Visual Studio Code and AL, we've seen and referred to variables in a number of situations. Some of the following are obvious, but for clarity's sake, we'll summarize them here.

In Chapter 3, Data Types and Fields, we reviewed various data types for variables that are defined within objects (referred to in Chapter 3, Data Types and Fields, as working storage data). Working storage consists of all of the variables that are defined for use within an object, but whose contents disappear when the object closes. Working storage data types, as discussed in Chapter 3, Data Types and Fields, are those that can be defined in either the AL global variables or AL local variables tabs. Variables can also be defined in several other places in a Business Central object.

AL Globals

Global variables are defined on the var section of each object in AL.

Global variables should be avoided. Dynamics Business Central legacy code has inherited many of them from the MS-DOS era of the product (called Navision or Navigator) when local variables were not available.

Global text constants are defined as variables. The primary purpose of the text constants area is to allow for easier translation of messages from one language to another. By putting all message text in this one place in each object, a standardized process can be defined for language translation.

Procedures are most often defined at the end of an AL file. The following screenshot provides an example of this:

AL Locals

Local identifiers only exist if they're defined within the range of a procedure or trigger. This is true if the trigger is a developer-defined procedure, one of the default system triggers, or a standard application-supplied procedure.

Procedure-local identifiers and return values are declared in the definition of the procedure.

The Variables and Text Constants tabs for AL Locals are the same in use to the AL Globals when using the var keyword. The declaration of the AL Locals form can be seen in the following screenshot:

Special working storage variables

Some working storage variables have additional attributes to be considered.

Temporary tables

Temporary tables were discussed in Chapter 2, Tables. Let's take a quick look at how one is defined. Defining a temporary table begins just like any other variable definition of the Record data type. To make it temporary, we add the temporary keyword after the table name, as shown in the following screenshot:

We can use a temporary table just as though it were a permanent table, with some specific differences:

  • The table only contains the data we add to it during this instance of the object in which it resides.
  • We cannot change any aspect of the definition of the table, except by changing the permanent table.
  • Processing for a temporary table is done wholly in the client system, in a user-specific instance of the business logic. It is, therefore, inherently a single user.
  • A properly utilized temporary table reduces network traffic and eliminates any locking...

AL programming

Many of the things that we do during development in Visual Studio Code might not be called programming by some people as it doesn't involve writing AL code statements. However, so long as these activities contribute to the definition of the object and affect the processing that occurs, we'll include them in our broad definition of AL programming.

These activities include setting properties at the object and DataItem levels, creating request pages in reports, defining controls and their properties, defining report data structures and their properties, creating source expressions, defining procedures, and, of course, writing AL statements in all of the places where we can put AL. We will focus on programming primarily as it relates to tables, reports, and codeunits.

We will touch on programming for pages and XMLports. In the case of reports, AL statements can reside only in the components that are developed within the report designer.

Business Central objects are...

Non-modifiable procedures

A procedure is a defined set of logic that performs a specific task. Similar to many other programming languages, AL includes a set of prewritten procedures that are available to us to perform a wide variety of different tasks. The underlying logic for some of these procedures is hidden and not modifiable. These non-modifiable procedures are supplied as part of the AL programming language. Some simple examples of non-modifiable procedures are as follows:

  • DATE2DMY: Supply a date to this procedure and, depending on a calling parameter, it will return the integer value of the day, month, or year of that date
  • STRPOS: Supply a string variable and a string constant to this procedure and it will return the position of the first instance of that constant within the variable, or a zero, if the constant is not present in the string that's contained in the variable
  • GET: Supply a value and a table to this procedure and it will read the record in the table with a primary...

Modifiable procedures

In addition to the prewritten language component procedures, there are a large number of prewritten application component procedures. The difference between the two types is that the code implementing the latter is visible and modifiable through cloning, though we should be extremely cautious about making such clones.

An example of an application component procedure might be one to handle the task of processing a customer's shipping address to eliminate empty lines and standardize the layout based on user-defined setup parameters. Such a procedure would logically be placed in a codeunit and hence made available to any routine that needs this capability.

In fact, this procedure exists. It is called SalesHeaderShipTo and is located in the Format Address codeunit. We can explore the following codeunits for some procedures we might find useful to use or that we can borrow logic from. This is not an all-inclusive list, as there are many procedures in other codeunits...

Custom procedures

We can also create our own custom procedures to meet any need. The most common reason to create a new procedure is to provide a single, standardized instance of logic to perform a specific task. When we need to use the same logic in more than one place, we should consider creating a callable procedure.

We should also create a new procedure when we're modifying standard Business Central processes through events. Our procedure then becomes an event subscriber.

If a new procedure is going to be used in several objects, it should be housed in our library codeunit (we may choose to have multiple library codeunits for the purpose of clarity or project management). If a new procedure is only for use in a single object, then it can be resident in that object. This latter option also has the advantage of allowing the new procedure direct access to the global variables within the object being modified, if necessary.

Creating a procedure

Let's take a quick look at how a procedure can be created. We'll use the small date formula app we created in Chapter 3, Data Types and Fields, and add a new codeunit, Codeunit 50141. We will call it Date Formula Management.

When working on projects with larger teams, creating more codeunits is advised so that you have a better chance of each developer working on separate objects.

We will create our new codeunit by simply clicking on New File in the File menu, then choosing File | Save As, and entering Codeunit 50141 Date Formula Mgt. We will select the codeunit snippet and populate the variables.

Now comes the important part—designing and coding our new procedure. When we had the procedure operating as a local procedure inside the table where it was called, we didn't worry about passing data back and forth. We simply used the data fields that were already present in the table and treated them as global variables, which they were. Now that our...

AL syntax

AL syntax is relatively simple and straightforward. The basic structure of most AL statements is essentially similar to what you learned with other programming languages. AL is modeled on Pascal and tends to use many of the same special character and syntax practices as Pascal.

Assignment and punctuation

Assignment is represented with a colon followed by an equal sign, the combination being treated as a single symbol. The evaluated value of the expression, to the right of the assignment symbol, is assigned to the variable on the left-hand side, as shown in the following line of code:

"Phone No." := '312-555-1212'; 

All statements are terminated with a semicolon. Multiple statements can be placed on a single program line, but that makes the code hard for others to read.

Fully qualified data fields are prefaced with the name of the record variable that they are a part of (see the preceding code line as an example of where the record variable is named Phone No.). The same structure applies to fully qualified procedure references; the procedure name is prefaced with the name of the object that they are defined in.

Single quotes are used to surround string literals (see the phone number string in the preceding line of code).

Double quotes are...

Expressions

Expressions in AL are made up of four elements—constants, variables, operators, and procedures. We could include a fifth element, expressions, because an expression may include a subordinate expression within it. As we become more experienced in coding AL, we will find that the capability of nesting expressions can be both a blessing and a curse, depending on the specific use and readability of the result.

We can create complex statements that will conditionally perform important control actions and operate in much the same way that a person would think about a task. We can also create complex statements that are very difficult for a person to understand. These are tough to debug and sometimes almost impossible to deal with in a modification.

One of our responsibilities is to be able to tell the difference so that we can write code that makes sense in operation, but is also easy to read and understand.

According to the Business Central Docs, an AL expression (https...

Operators

Now, we'll review AL operators grouped by category. Depending on the data types we are using with a particular operator, we may need to know the type conversion rules by defining the allowed combinations of operator and data types for an expression. The Business Central docs provides good information on type conversion rules. Search for the phrase type Conversion to learn more.

Before we review the operators that can be categorized, let's discuss some operators that don't fit well into any of the categories. These include the following:

Explanations regarding the use of the operator symbols in the preceding table are as follows:

  • The symbol represented by a single dot or period doesn't have a given name in the Business Central documentation, so we'll call it the member symbol or dot operator (as it is referred to in the MSDN Visual Basic Developer documentation). It indicates that a field is a member of a table (TableName.FieldName), a control...

Arithmetic operators and procedures

The arithmetic operators include the following set of operators:

As we can see, in the Data Types column, these operators can be used on various data types. Numeric types include Integer, Decimal, Boolean, and Character data types. Text and Code are both String data.

Sample statements using DIV and MOD are shown in the following code, where BigNumber is an integer containing 200:

DIVIntegerValue := BigNumber DIV 60; 

The contents of DIVIntegerValue, after executing the preceding statement, will be 3:

MODIntegerValue := BigNumber MOD 60; 

The contents of MODIntegerValue, after executing the preceding statement, will be 20.

The syntax for these DIV and MOD statements is as follows:

IntegerQuotient := IntegerDividend DIV IntegerDivisor; 
IntegerModulus := IntegerDividend MOD IntegerDivisor; 

Boolean operators

Boolean operators only operate on expressions that can be evaluated as Boolean. These are shown in the following table:

The result of an expression based on a Boolean operator will also be Boolean.

Relational operators and procedures

The relational operators are listed in the following screenshot. Each of these is used in an expression of the following format:

Expression RelationalOperator Expression 

An example is (Variable1 + 97) > ((Variable2 * 14.5) / 57.332). The following operators can be used:

We will spend a little extra time on the IN operator, because this can be very handy and is not documented elsewhere. The term Valueset in the Evaluation column for IN refers to a list of defined values. It would be reasonable to define Valueset as a container of a defined set of individual values, expressions, or other value sets. Some examples of IN, as used in the standard Business Central product code, are as follows:

GLEntry."Posting Date" IN [0D,WORKDATE] 
 
Description[I+2] IN ['0'..'9'] 
 
"Gen. Posting Type" IN ["Gen. Posting Type"::Purchase, "Gen. Posting Type"::Sale] 
 
SearchString IN ['',&apos...

Precedence of operators

When expressions are evaluated by the AL compiler, the parsing routines use a predefined precedence hierarchy to determine what operators to evaluate first, what to evaluate second, and so forth. This precedence hierarchy is provided in the Business Central Docs section, C/AL Operators – Operator Hierarchy (https://msdn.microsoft.com/en-us/dynamics-nav/c-al-operators), but for convenience, the information is repeated here:

For complex expressions, we should always freely use parentheses to make sure that the expressions are evaluated the way we intend them to be.

Frequently used AL procedures

It's time to learn about more of the standard procedures that are provided by Microsoft. We will focus on the following short list of frequently used procedures: MESSAGE, ERROR, CONFIRM, and STRMENU.

There is a group of procedures in AL called Dialog procedures. The purpose of these procedures is to allow communication, that is, dialog, between the system and the user. In addition, the Dialog procedures can be useful for quick and simple testing/debugging. To make it easier for us to proceed with our next level of AL development work, we'll take time now to learn about these four dialog procedures. None of these procedures will operate if the AL code is running on the Business Central job queue as it has no GUI available. To handle that situation in previous versions of Business Central, the Dialog procedure statements had to be conditioned with the GUIALLOWED procedure to check whether or not the code was running in a GUI allowed environment...

The MESSAGE procedure

MESSAGE is easy to use for the display of transient data and can be placed almost anywhere in our AL code. All it requires of the user is acknowledgement that the message has been read. The disadvantage of messages is that they are not displayed until either the object completes its run or pauses for some other external action. Plus, if we inadvertently create a situation that generates hundreds or thousands of messages, there is no graceful way to terminate their display once they are displaying.

It's common to use MESSAGE as the elementary trace tool. We can program the display of messages to occur only under particular circumstances and use them to view either the flow of processing (by outputting simple identifying codes from different points in our logic) or to view the contents of particular data elements through multiple processing cycles.

To display information to the user without interrupting them in their work, notifications can be used. You can learn...

The ERROR procedure

When an ERROR procedure is invoked, the execution of the current process terminates, the message is immediately displayed, and the database returns to the status it had following the last (implicit or explicit) COMMIT procedure as though the process that was calling the ERROR procedure had not run at all.

We can use the ERROR procedure in combination with the MESSAGE procedure to assist in repetitive testing. MESSAGE procedures can be placed in code to show what is happening with an ERROR procedure that's been placed just prior to where the process would normally complete. Because the ERROR procedure rolls back all database changes, this technique allows us to run through multiple tests against the same data without any time-consuming backup and restoration of our test data. The enhanced testing procedurality that's built into Business Central can accomplish the same things in a much more sophisticated fashion, but sometimes there's room for a temporary...

The CONFIRM procedure

A third dialog procedure is the CONFIRM procedure. A CONFIRM procedure call causes processing to stop until the user responds to the dialog. In CONFIRM, we will include a question in our text because the procedure provides Yes and No button options. The application logic can then be conditioned on the user's response.

We can also use CONFIRM as a simple debugging tool to control the path the processing will take. Display the status of data or processing flow and then allow the operator to make a choice (Yes or No) that will influence what happens next. Execution of a CONFIRM procedure will also cause any pending MESSAGE procedure output values to be displayed before the CONFIRM procedure displays. Combined with MESSAGE and ERROR, creative use of CONFIRM can add to our elementary debugging/diagnostic toolkit.

CONFIRM has the following syntax:

BooleanValue :=  CONFIRM(String [, Default]  [, Value1]  ,...)  

When we do not specify a value for Default, the system...

The STRMENU procedure

A fourth dialog procedure is the STRMENU procedure. A STRMENU procedure call also causes processing to pause while the user responds to the dialog. The advantage of the STRMENU procedure is its ability to provide several choices, rather than just two (Yes or No). A common use is to provide an option menu in response to the user pressing a command button.

STRMENU has the following syntax:

IntegerValue := STRMENU(StringVariable of Options separated by commas  
[, OptionDefault][, Instruction]) 

IntegerValue will contain the user's selection entry, and OptionDefault is an integer representing which option will be selected by default when the menu displays. If we do not provide an OptionDefault value, the first option that's listed will be used as the default. Instruction is a text string that will display the preceding list of options. If the user responds with Cancel or presses the Esc key, the value that's returned by the procedure is 0.

Use...

Record procedures

Now, we will review some of the procedures that we commonly use in record processing.

The SETCURRENTKEY procedure

The syntax for SETCURRENTKEY is as follows:

[BooleanValue :=] Record.SETCURRENTKEY(FieldName1,[FieldName2], ... )                  

Because Business Central is based on the SQL Server database, SETCURRENTKEY simply determines the order in which the data will be presented for processing. The actual choice of the index to be used for the query is made by the SQL Server Query Analyzer. For this reason, it is very important that the data and resources available to the SQL Server Query Analyzer are well maintained. This includes maintaining the statistics that are used by the Query Analyzer, as well as making sure that efficient index options have been defined. Even though SQL Server picks the actual index, the developer's choice of the appropriate SETCURRENTKEY parameter can have a major affect on performance.

The fields that are used in the SETCURRENTKEY command do not have to match a key in the table definition. You can also use FlowFields as fields for...

The SETRANGE procedure

The SETRANGE procedure provides the ability to set a simple range filter on a field. The SETRANGE syntax is as follows:

Record.SETRANGE(FieldName [,From-Value] [,To-Value]);

Prior to applying its range filter, the SETRANGE procedure removes any filters that were previously set for the defined field (filtering procedures are defined in more detail in the next chapter). If SETRANGE is executed with only one value, that one value will act as both the From and To values. If SETRANGE is executed without any From or To values, it will clear the filters on the field. This is a common use of SETRANGE. Some examples of the SETRANGE procedure in code are as follows:

  • Clear the filters on Item.No.:
Item.SETRANGE("No."); 
  • Filter to get only items with No. from 1300 through 1400:
Item.SETRANGE("No.",'1300','1400');  
  • Alternatively, you can use the variable values from LowVal through HiVal:
Item.SETRANGE("No.",LowVal...

The SETFILTER procedure

SETFILTER is similar to, but much more flexible than, the SETRANGE procedure because it supports the application of any of the supported Business Central filter procedures to table fields. The SETFILTER syntax is as follows:

Record.SETFILTER(FieldName, FilterExpression [Value],...); 

The FilterExpression consists of a string (text or code) in standard Business Central filter format, including any of the operators (<, >, *, &, |, and =) in any legal combination. Replacement fields (%1, %2, ..., %9) are used to represent the values that will be inserted into FilterExpression by the compiler to create an operating filter that's formatted as though it were entered from the keyboard. Just like SETRANGE, prior to applying its filter, the SETFILTER procedure clears any filters that were previously set for the defined field, as in the following example:

  • Filter to get only items with No. from 1300 through 1400:
Item.SETFILTER("No."...

The GET procedure

GET is the basic data retrieval procedure in AL. GET retrieves a single record based on the primary key only. It has the following syntax:

[BooleanValue :=] Record.GET ( [KeyFieldValue1] [,KeyFieldValue2] ,...) 

The parameter for the GET procedure is the primary key value (or all of the values, if the primary key consists of more than one field).

Assigning the GET procedure result to BooleanValue is optional. If the GET procedure is not successful (no record found) and the statement is not part of an IF statement, the process will terminate with a runtime error. Typically, therefore, the GET procedure is encased in an IF statement, which is structured like so:

IF Customer.GET(NewCustNo) THEN ... 
GET data retrieval is not constrained by filters, except for security filters (see help, How to: Set Security Filters at https://msdn.microsoft.com/en-us/library/hh166853(v=nav.90).aspx). If there is a matching record in the table, GET will retrieve it.

FIND procedures

The FIND family of procedures is the general purpose data retrieval procedure in AL. It is much more flexible than GET, and therefore more widely used. GET has the advantage of being faster as it operates only on unfiltered direct access through the primary key, looking for a single uniquely keyed entry. There are two forms of FIND procedures in AL, one a remnant from a previous database structure and the other designed specifically to work efficiently with SQL Server. Both are supported, and we will find both in standard code.

The older version of the FIND procedure has the following syntax:

[BooleanValue :=] RecordName.FIND ( [Which] ). 

The newer SQL Server-specific members of the FIND procedure family have slightly different syntax, as we will see shortly.

Just like the GET procedure, assigning the FIND procedure result to a Boolean value is optional. However, in almost all of the cases, FIND is embedded in a condition that controls subsequent processing appropriately...

FIND ([Which]) options and the SQL Server alternatives

Let's review the FIND procedure option's syntax variations:

[BooleanValue :=] RecordName.FIND ( [Which] ) 

The [Which] parameter allows you to specify which record is searched for, relative to the defined key values. The defined key values are the set of values currently in the fields of the active key in the memory-resident record of the RecordName table.

The following table lists the Which parameter options and prerequisites:

The second table lists the FIND options, which are specific to SQL Server, as follows:

For all FIND options, the results always respect the applied filters.

The FIND('-') procedure is sometimes used as the first step of reading a set of data, such as reading all of the sales invoices for a single customer. In such a case, the NEXT procedure is used to trigger all subsequent data reads after the sequence is initiated with FIND('-'). Generally, FINDSET should be used...

Conditional statements

Conditional statements are the heart of process flow structure and control.

The BEGIN-END compound statement

In AL, there are instances where the syntax only allows the use of a single statement. However, a design may require the execution of several (or many) code statements.

AL provides at least two ways to address this need. One method is to have the single statement call a procedure that contains multiple statements.

However, inline coding is often more efficient to run and understand. So, AL provides a syntax structure to define a compound statement or block of code. A compound statement containing any number of statements can be used in place of a single code statement.

A compound statement is enclosed by the reserved words BEGIN and END. The compound statement structure looks like this:

BEGIN 
  <Statement 1>; 
  <Statement 2>; 
  .. 
  <Statement n>; 
END 

The AL code contained within a BEGIN-END block should be indented by two characters, as shown in the preceding pseudocode snippet, to make it obvious that it is a block of code.

IF-THEN-ELSE statement

IF is the basic conditional statement of most programming languages. It operates in AL much the same as how it works in other languages. The basic structure is as follows: IF a conditional expression is true, THEN execute Statement-1 or (if condition is not true) execute Statement-2. The ELSE portion is optional. The syntax is as follows:

IF <Condition> THEN <Statement-1> [ ELSE <Statement-2> ] 

Note that the statements within an IF statement do not have terminating semicolons, unless they are contained in a BEGIN-END framework. IF statements can be nested so that conditionals are dependent on the evaluation of other conditionals. Obviously, you need to be careful with such constructs, because it is easy to end up with convoluted code structures that are difficult to debug and difficult for the developers following us to understand. In the next chapter, we will review the CASE statement that can make some complicated conditionals...

Indenting code

Since we have just discussed the BEGIN-END compound statements and the IF conditional statements, which also are compound (that is, containing multiple expressions), this seems like a good time to discuss indenting code.

In AL, the standard practice for indenting subordinate, contained, or continued lines is relatively simple. Always indent such lines by two characters, except where there are left and right parentheses to be aligned.

To indent a block of code two characters at a time with the Business Central AL code editor, select them and click on the Tab key. To remove the indentation one character at a time, select the code and click on Shift Tab.

In the following examples, the parentheses are not required in all of the instances, but they don't cause any problems and can make the code easier to read.

Some examples are as follows:

IF (A <> B) THEN 
   A := A + Count1 
ELSE 
  B := B + Count2; 

Or here's another:

IF (A <> B) THEN 
 ...

Some simple coding modifications

Now, we'll add some AL code to objects we've created for our WDTU application.

Adding field validation to a table

In Chapter 4, Pages The Interactive Interface, we created the 50110 "Radio Show Fan" table. We've decided that we want to be able to use this list for promotional activities, such as having drawings for concert tickets. Of course, we want to send the tickets to the winners at their mailing addresses. We didn't include these fields originally in our table design, so we must add them now.

To keep our design consistent with the standard product, we will model these fields after the equivalent ones in the 18 - Customer table. Our updated table, 50110, will look as follows:

Part of modeling our 50110 "Radio Show Fan" table fields on those in the 18 - Customer table is faithfully copying the applicable properties. For example, the TableRelation property for the Post Code field in table 18 contains the following lines of code, which we should include for the Post Code field in table...

Adding code to a report

Most reports require some embedded logic to process user selected options, calculate values, or access data in related tables. To illustrate some possibilities, we will extend our WDTU application to add a new report.

To support promotions giving away posters, concert tickets, and so on, we must further enhance the Radio Show Fan table and create a new report to generate mailing information from it. Our first step is to create a new dataset in the Visual Studio Code IDE. We should define the data fields we want to include for mailings (including a global variable of CountryName), then save and compile the result as a report called 50102 "Fan Promotion List", as shown in the following screenshot:

Laying out the new Report Heading

Next, we will begin the design of the report layout in Microsoft Word. If we build our application, a Word template will be created, which we can open externally.

We will add a report header by simply creating it with a default style, as shown in the following screenshot:

Saving and testing

At this point, it's time to save and test what we've done so far. Exit from Microsoft Word. Save the report layout changes. Build and publish your application and run the report using the search.

This first test is very simple (assuming it works). The Report Request Page will appear in the web client. Click on Preview to see the report display on-screen. The layout shown in the preceding screenshot will result in the following report page (or something similar):

Laying out the new report Body

Open the report layout in Microsoft Word. From the ribbon, we'll grab a table and drag it into the layout work area for the report body. The table should contain five columns and two rows.

We will add the data fields from the XML mapping into each of the data row text boxes (the bottom row). In the top row, we will type captions. We will make the second row a repeating row:

Saving and testing

After we lay out, save and exit, update, and save and build, it's time to do another test run of our report in process. If we simply preview it without doing any filtering, we should see all of our test data address information (complete with country name), as shown in the following screenshot:

Handling user entered report options

Part of our report design includes allowing the user to choose fans based on some simple demographic data, such as age and gender. We'll need to add two more fields to our Radio Show Fan table definition, one for Gender and the other for Birth Date, from which we can calculate the fan's age, as shown in the following screenshot:

This back and forth process of updating one object, then a different one, then yet another, is typical of the Business Central development process most of the time. Exceptions are those cases where either the task is so simple we think of everything the first time through, or the cases where we create a completely documented, full-featured design before any development starts (but nobody thinks of everything, there are always changes; our challenge is to keep the changes under control).

An advantage to the more flexible approach we are following is that it allows us to view (and share with others) intermediate versions...

Defining the Request Page

Now, let's define the requestpage. Click on View | Request Page and make the entries necessary to describe the page's contents, as shown in the following screenshot:

Finishing the processing code

Next, we will create the AL code to calculate a fan's age (in years) based on their birth date and the current WORKDATE. The logic is simple—subtract the birthdate from the WORKDATE. This gives a number of days. So, we will divide by 365 (not worrying about leap years) and round down to integer years (if someone is 25 years, 10 months, and 2 days old, we will just consider them 25). In the following code, we did the division as though the result were a decimal field. However, because our math is done in integers, we could have used the simpler expression:

FanAge := ((WORKDATE - "Birth Date") DIV 365); 

Finally, we'll write the code to check each Fan record data against our selection criteria, determining whether we want to include that fan in our output data (SelectThisFan set to True). This code will select each fan who fits any of the checked criteria; there is no combination logic here.

The following is our commented AL code...

Testing the completed report

After we save and compile our report, we'll run it again. Now, we will get an expanded request option page. After this, we check-marked a couple of the selection criteria, as shown in the following screenshot:

Now, let's preview our report. Using the sample data we previously illustrated, our report output shows two records in the following screenshot; one selected on the basis of Gender and the other on Age:

At this point, we have a report that runs and is useful. It can be enhanced to support more complex selection criteria. As usual, there are a number of different ways to accomplish essentially the same result. Some of those paths would be significantly different for the developer, but nearly invisible to the user. Some might not even matter to the next developer who has to work on this report. What is important at this point is that the result works reliably, provides the desired output, operates with reasonable speed, and does not cost too...

Summary

"Furniture or gold can be taken away from you, but knowledge and a new language can easily be taken from one place to the other, and nobody can take them away from you."
– David Schwarzer

In this chapter, we covered Visual Studio Code navigation. We covered a number of AL language areas, including procedures and how they may be used, variables of various types (both development and system), basic AL syntax, expressions, and operators. Some of the essential AL procedures that we covered included user dialogs, SETRANGE filtering, GET, variations of FIND, and BEGIN-END for code structures, plus IF-THEN for basic process flow control. Finally, we got some hands-on experience by adding validation code to a table and creating a new report that included embedded AL code and a request page.

In the next chapter, we will expand our exploration and practice using AL. We will learn about additional AL procedures, flow control structures, input/output procedures, and...

Questions

  1. All Business Central objects can contain AL codetrue or false?
  2. Which object type has to be designed outside of Visual Studio Code? Choose one:
  • Page
  • XmlPort
  • Table
  • Report
  1. All AL Assignment statements include the symboltrue or false?
  2. One setting defines how parameters are passed to procedures, that is, whether a parameter is passed by reference or by value. Choose that one setting identity:
  • DataType
  • Subtype
  • Var
  • Value
  1. In Visual Studio Code, we can use wizards to get started with object definitionstrue or false?
  2. The AL code cannot be inserted into the RDLC generated by the Visual Studio Report Designer (or the SQL Server Report Builder)true or false?
  3. When a table definition is changed, the fields should always be added to all pagestrue or false?
  4. Object numbers and names are so flexible that we can (and should) choose our own approach to numbering and namingtrue or false?
  5. BEGIN-END are always required in IF statements...
lock icon
The rest of the chapter is locked
You have been reading a chapter from
Programming Microsoft Dynamics 365 Business Central - Sixth Edition
Published in: Apr 2019Publisher: PacktISBN-13: 9781789137798
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €14.99/month. Cancel anytime

Authors (3)

author image
Marije Brummel

Author, programmer, consultant, project manager, presenter, evangelist, sales person, and a trainer. It's next to impossible to find someone as experienced as Marije Brummel in the Business Central community. Marije received the Microsoft MVP and the NAVUG All-Star awards among several others. She has chaired the Dynamics Credentialing committee and has authored official Microsoft Exam materials. She's the go-to girl for performance troubleshooting and upgrade challenges. One of her biggest achievements was introducing Design Patterns into the Business Central community. Her books, blog articles, and YouTube videos have influenced almost everyone involved with Business Central. She enjoys the outdoors with her dog and loves spending time with her family.
Read more about Marije Brummel

author image
David Studebaker

David Studebaker has been designing and developing software since 1962 as a developer, consultant, manager, and business owner. In 1967, David coauthored the first general-purpose SPOOL system, an AT&T / IBM joint project. He has been a founding partner in several firms, most recently Studebaker Technology and Liberty Grove Software. David's publications include a decade of technical reviews for ACM Computing Reviews and a number of articles on shop floor data collection. David originated the Packt series of books on programming Dynamics Business Central (aka Dynamics NAV). He has a BS in mechanical engineering from Purdue University and an MBA from the University of Chicago. He is a life member of the Association for Computing Machinery.
Read more about David Studebaker

author image
Christopher D. Studebaker

Chris Studebaker was a certified environmental consultant working with manufacturing facilities to meet national and state regulations before he started working with Navision in 1999. After working on regulatory reporting, data analysis, project management, and subcontractor oversight, Chris has used those skills to sell, develop, and implement NAV for the past 20 years. He has specialized in retail, manufacturing, job shop, and distribution implementations, mostly in high-user-count, high-data-volume applications. Chris acts in a consulting and training role for customers and for peer NAV professionals. He has a Bachelor of Science degree from Northern Illinois University and has done graduate work at Denmark Technical University.
Read more about Christopher D. Studebaker