01 Rules GXXEv2Course(Deepening)

download 01 Rules GXXEv2Course(Deepening)

of 12

Transcript of 01 Rules GXXEv2Course(Deepening)

  • 7/31/2019 01 Rules GXXEv2Course(Deepening)

    1/12

    Rules play a very important role in transaction objects, as they allow you to program their behavior (forexample: assigning default values, defining controls over the data, etc.).

    They are written in a declarative way, which means the order in which they are written is not necessarily theorder in which they will be executed.

    They may involve the attributes defined in the transaction's structure1, as well as variables defined withinthe object, constants and functions.

    They are only valid within the transaction in which they are defined, that is to say, they are local.

    -----------------------------------------------------------------------------------------------------------------------------------------------------------------

    1 All transaction rules can involve attributes of the base tables associated to the transaction; and most rules can also involveattributes of the extended tables of such base tables.

  • 7/31/2019 01 Rules GXXEv2Course(Deepening)

    2/12

    Some valid rules for transactions are:

    Default

    OBJECTIVE: It allows you to assign a default value to an attribute or variable; the default value will initialize the attributeor variable if an insertion is being made through the transaction (Insert mode), but the end user can change it if it's notthe desired value.

    SYNTAX: Default( att| &var, exp);

    WHERE: att: is an attribute that belongs to one of the base tables associated to the transaction. var: is the name of a variable. exp: is an expression that can involve constants, functions, variables or other attributes.

    FUNCTIONALITY: This rule assigns the value of the expexpression as default value of the attattribute orvarvariable,when the transaction is executed in Insert mode.

    This rule is not valid for attributes that are part of the primary key of one of the transaction levels, because it is triggeredafter the key is entered (as only then is that particular mode known, and this rule is only triggered in Insert mode).

    EXAMPLES:Default(InvoiceDate, &today); /*Rule defined in the Invoice transaction*/

    When a new invoice is being inserted, the value suggested for InvoiceDate is the value contained in

    the variable of the todaysystem.

    Default( InvoiceDate, Today()); /*Rule defined in the Invoice transaction*/

    It is analogous to the previous one, only that instead of using a variable from the today, system, theToday function, which returns the date of the corresponding day, is used.

    Default( InvoiceDetailAmount, ProductPrice*InvoiceDetailQuantity); /* Rule defined in the Invoice transaction*/

    When an invoice line is being inserted, it is suggested that the InvoiceDetailAmountattribute take the value that resultsfrom evaluating the ProductPrice*InvoiceDetailQuantity expression (price of the product times quantity of productpurchased).

    Note: The data type of the expression must match the data type of the attribute or variable

    Allocation rule

    OBJECTIVE: It is used for assigning the value of an expression to an attribute or a variable.

    SYNTAX: att |&var=exp[ifcond] [onevent/trigger time];

    WHERE: att:is an attribute that belongs to one of the base tables associated to the transaction, or to its extended tables (it mustbe declared in the structure). var:is the name of a variable. exp:is an expression that can involve constants, functions, variables or other attributes, and must be of the same typeas the attorvar. cond: is a Boolean expression (that can contain the "and", "or", and "not" logical operators) event/trigger time:is one of the predefined events that is available in GeneXus for transaction rules,

    allowing you to define the precise moment for executing a rule.

    FUNCTIONALITY: This type of rule allows you to assign to the attribute or variable on the left the value that results fromevaluating the expression. As is evident, the condition is optional; if it's not included, the allocation will always beperformed.

    An allocation to an attribute entails that the attribute is updated in the corresponding record.. You can define rules forallocating to attributes of any of the base tables associated to the transaction. This also applies to its extended tables.This means that inferred attributes in a transaction can be updated (but they must be declared in the structure).

  • 7/31/2019 01 Rules GXXEv2Course(Deepening)

    3/12

    EXAMPLE:

    InvoiceDetailAmount= ProductPrice*InvoiceDetailQuantity; /*Rule defined in the Invoice transaction*/

    If the amount of each invoice line is always calculated multiplying the price of the product by the amount of productpurchased, we can use this rule to free users from having to perform this calculation.

    Error

    OBJECTIVE: It is used to display an error message if the condition is met. It enables you to define controls that must be

    satisfied by the data.

    SYNTAX: Error(msg | &var| character expression, msgId)ifcond [onevent/trigger time];

    WHERE: msg: is a string with an error message to be displayed. var: is the name of a character-type variable that contains a string with an error message to be displayed. character expression: is an expression whose resulting type is character and which will be displayed.msgId: is a string (without blank spaces or quotes) that will only be used if the transaction is also defined as businesscomponent1.cond: is a Boolean expression (that can contain the "and", "or", and "not" logical operators) event/trigger time:is one of the predefined events available in GeneXus for transaction rules, which allows you to define theprecise moment for executing a rule.

    FUNCTIONALITY: This rule displays the message from the msg, var or character expression parameter, if the condcondition being evaluated is true. The error message is displayed in a pop-up window when working in a Windowsenvironment, and in the Error Viewer control and/or a text box when working in a Web environment, and stops any updatesin the database. When the transaction is executed as business component (we will study this issue later on in the course), ifan error is triggered, an entry in the SDT messages, with msgIdidentifier, will be generated.

    EXAMPLES:

    Error(Customers without a name are not allowed)ifCustomerName.isEmpty();/*Rule defined in the Customer transaction*/

    The CustomerName.isEmpty() condition is evaluated, and if met, the Customers without a name are not allowed messageis displayed on screen. Users will not be allowed to continue until they enter a name in the CustomerNamefield or abandonthe transaction (in which case no update will be made in the database).

    Error(Invoices cannot be deleted) ifDelete;/*Rule defined in the Invoice transaction*/

    You don't want to allow invoice deletion. With this rule, whenever users try to delete an invoice, the condition will be True andthe rule will be triggered, thus preventing deletion.

    Msg

    OBJECTIVE: It is used to display a warning message if the condition is met.

    SYNTAX: Msg( msg | &var| character expression, msgId)ifcond [onevent/trigger time];

    WHERE:msg, var, character expression, msgId, cond, event/trigger time:are the same as in the error rule.

    Note that the syntax is exactly the same.

    FUNCTIONALITY: This rule is used to present warning messages to the user. It displays the message from the firstparameter, if the condition is met, similarly to the Error rule; but unlike the error rule it allows users to continue with executionif the condition is still met. Likewise, when performing a business component1 transaction, if the rule is triggered it willgenerate an entry in the SDT messages.

    The warning messages are displayed in the Error Viewer.

  • 7/31/2019 01 Rules GXXEv2Course(Deepening)

    4/12

    EXAMPLE:

    Msg(Customers without a name are not allowed ) ifCustomerName.isEmpty();/*Rule defined in the Customer transaction*/

    The CustomerName.isEmpty() condition is evaluated, and if met, the Customers without a name are not allowed messageis displayed on screen. Unlike what happens with the Error rule, in this case users are allowed to continue with execution, asthere is no error here, only a warning.

    Noaccept

    OBJECTIVE: It is used to indicate that the attributes will not accept values from users (they will only be display attributes).

    SYNTAX: Noaccept( att1[, atti]) [ifcond];

    WHERE:atti:is an attribute that belongs to one of the base tables associated to the transaction.cond: is a Boolean expression (that can contain the "and", "or", and "not" logical operators).event/trigger time:is one of the predefined events available in GeneXus for transaction rules, which allows you to define theprecise moment for executing a rule.

    FUNCTIONALITY: In a transaction, all the attributes that belong to the base tables associated to the transaction areaccepted by default. If we want for any such attributes not to be accepted, we can use the Noaccept rule.

    EXAMPLE:Noaccept(IvoiceDate) if Update;/* Rule defined in the Invoice transaction*/

    If you're modifying an invoice (Update mode), you will not be able to change the date.

    Subtract

    OBJECTIVE: It subtracts the value of one attribute from the value of another attribute, if the specified condition is met.

    SYNTAX: subtract(att1, att2) [ifcond];

    WHERE:att1, att2: are attributes that belong to one of the base tables associated to the transaction, or to its extended tables (it must

    be declared in the structure).cond: is a Boolean expression (that can contain the "and", "or", and "not" logical operators).

    FUNCTIONALITY: Subtractions are performed taking into account the mode selected to work in the transaction (Insert,Update or Delete).

    In mode:- Insert: the value of the att1 attribute is subtracted from the value of the att2attribute- Delete: the value of the att2attribute is added to the value of the att1 attribute- Update: the difference between the new and old value of the att1 attributeis subtracted from the value of theatt2 attribute

    EXAMPLE:

    In the Invoice transaction, every time a line is added with a product that is being purchased, the amount of stock for thatproduct must be reduced according to the amount purchased.

    This can be done easily with the following allocation rule:

    ProductStock= ProductStockInvoiceDetailQuantity;

    On a closer look, though, we see that this rule is no good here, because it is not conditioned to a particular mode, whichmeans it will be triggered both when a new line is inserted in the invoice and when an existing line is deleted or modified

    And triggering this rule in these last two cases would be incorrect.

  • 7/31/2019 01 Rules GXXEv2Course(Deepening)

    5/12

    In fact, when deleting an existing line, the opposite operation must be performed; that is, whatever was removed from stock

    when the line was added must be returned to stock.

    In order to do this correctly, taking into account all possible cases, three rules must be used:

    ProductStock= ProductStockInvoiceDetailQuantityif Insert;ProductStock= ProductStock+ InvoiceDetailQuantityif Delete;ProductStock= ProductStock+ old(InvoiceDetailQuantity)InvoiceDetailQuantityif Update;

    Here we are using the old function, which returns the attribute's stored value (the value it had before it was modified). Inorder to avoid having to do all this, GeneXus provides the subtract rule, which allows the correct allocation to be made

    according to the mode. Thus we can replace the above three allocations with:

    subtract(InvoiceDetailQuantity, ProductStock);

    This rule is intelligent enough to subtract or add depending on the mode.

    Add

    OBJECTIVE: It adds the value of one attribute to the value of another attribute, if the specified condition is met

    SYNTAX: add( att1, att2) [ifcond];

    WHERE:

    att1, att2: are attributes that belong to one of the base tables associated to the transaction, or to its extended tables (they

    must be declared in the structure).cond:is a Boolean expression.

    FUNCTIONALITY: Additions are perfomed taking into account the mode selected to work in the transaction (Insert, Update

    or Delete).

    In mode:

    - Insert: the value of the att2attribute is added to the value of the att1 attribute

    - Delete: the value of the att1 attribute is subtracted from the value of the att2attribute

    - Update: the difference between the new and old value of the att1 attribute is added to the value of the att2attribute

    EXAMPLE:

    In the Customer transaction, we define an attribute with the name CustomerTotalPurchases to record the total amount ofpurchases made by the customer. The behavior we want is the following: each time an invoice is created for a given

    customer, the total of that invoice (InvoiceAmount) will be added to the purchases made by that customer

    (CustomerTotalPurchases).

    As in the subtract rule, we must not forget that in the Invoice transaction we can also delete and modify invoices, and not

    just create them; therefore, it is important to keep the working mode of the transaction in mind (Insert, Update, Delete)

    GeneXus frees us from having to consider the mode, and having to write the following three allocation rules in the "Invoice"

    transaction:

    CustomerTotalPurchases = CustomerTotalPurchases + InvoiceAmount if Insert;CustomerTotalPurchases = CustomerTotalPurchases InvoiceAmount if Delete;CustomerTotalPurchases = CustomerTotalPurchases old(InvoiceAmount) + InvoiceAmount if Update;

    instead it provides the add rule, which will determine whether to add or subtract, depending on the mode.

  • 7/31/2019 01 Rules GXXEv2Course(Deepening)

    6/12

    So if we add the CustomerTotalPurchases attribute (total purchases made by the customer) in the "Customer"transaction:

    CustomerId*CustomerNameCustomerAddressCustomerGender...CustomerTotalPurchases

    and in the Invoice transaction we infer the CustomerTotalPurchases, attribute, as it belongs to the extendedtable, and we can define the following rule:

    add(InvoiceAmount, CustomerTotalPurchases);

    and we obtain the desired behavior, which is:

    if an invoice is added (Insert): the value of the InvoiceAmount attribute is added to the value of theCustomerTotalPurchases attribute if an invoice is eliminated (Delete): the value of the InvoiceAmountattribute is subtracted from the value of theCustomerTotalPurchases attribute

    if an invoice is modified (Update): the difference between the new and old value of the InvoiceAmount attributeis added to the value of theCustomerTotalPurchases attribute

    Serial

    OBJECTIVE: It allows you to serially number numeric attributes.SYNTAX: Serial( att1, att2, step);

    WHERE:

    att1: is an attribute that belongs to one of the base tables associated to the transaction (that is, not inferred),which you wish to autonumber (it must be declared in the structure).

    att2: It must belong to a table directly superordinate to that of the att1 attribute.

    step: the serialization step or increment.

    FUNCTIONALITY: The purpose of this rule is to assign a consecutive number to att1 every tiem a record is

    inserted in the table that includes att1. To the value of att2 (att2 contains the last number used in theautonumbering), you add the value of the step parameter, and the resulting value is assigned both to the att1attribute of the new record, and to the att2 attribute to keep the last number assigned.

    That is, when you are inserting a record through a transaction where the following rule has been defined:Serial(att1, att2, step);, you access the att2 (there will be only one value of this related attribute, as it belongs to adirectly superordinate table1), you add the stepvalue, and you assign the obtained value both to att1 of the recordto be inserted and to att2belonging to a directly superordinate table with respect to the table that contains att1.

    If the Invoice transaction is designed with an Invoice Line Number (InvoiceDetailId attribute) as the uniqueidentifier of the second level, the transaction structure would be:

    INVOICE{

    InvoiceId*

    CustomerIdCustomerNameInvoiceDateInvoiceLastLineId

    Detail{InvoiceDetailId*ProductIdProductDescription

    }}

  • 7/31/2019 01 Rules GXXEv2Course(Deepening)

    7/12

    In this design, the ProductIdattribute is not a unique identifier of the level, it is a foreign key only.

    Each line has a line number that identifies it uniquely, and it is possible to enter the same product in different lines.

    It could be useful to assign, through the system, consecutive numbers to the InvoiceDetailIdfield, defining the followingrule:

    serial(InvoiceDetailId, InvoiceLastLineId, 1);

    The first parameter of the serial rule defines the attribute to be automatically numbered, in the second parameter you

    must indicate an attribute whose purpose is to save the last value assigned up to this point, and, lastly, the third

    parameter is used to indicate the increment (in this case, it is incremented one by one).

    The second parameter (in the example InvoiceLastLineId) must belong to a table directly superordinate to the table that

    contains the attribute you want to number automatically (InvoiceDetailId). The serial rule requires this. In the example,

    you can see that InvoiceLastLineIdis located in the table with key: InvoiceId*, which is directly superordinate with respectto the table that contains the attribute to be numbered (InvoiceDetailId).

    This means that each invoice will have in its header an attribute that will store the last line number assigned up to this

    point (InvoiceLastLineId). The serial rule is implemented in such a way that it needs this attribute (to find the last numberused, add the increment and allocate the next number to the new line).

    Consideration:The serial rule is useful for autonumbering lines, but not in the case of headers (for example, invoices or customers

    identifiers, etc.). The reason is the following: in order to use the serial rule, an attribute must be defined in a directly

    superordinate table; this is extremely easy if you want autonumbered lines, as all you have to do is include this attribute in

    the structure level that is immediately above that of the attribute you wish to autonumber.

  • 7/31/2019 01 Rules GXXEv2Course(Deepening)

    8/12

    However, we have an easier solution for autonumbering headers: when a table has a single key (that is, made up of a single

    attribute) and the data type is numeric, the automatic numbering can be performed using the functionality provided by the

    database managers for this purpose. To indicate this in GeneXus, you have to configure the Autonumber property of the key

    attribute:

    If in the Autonumber property of a key numeric attribute you select the True value, this means that it will be automaticallynumbered. The following properties will be added in the dialog:

    Start: This property is used to configure the number the automatic numbering starts at.

    Step: This property allows you to configure the field increment (between two records).

    For replication: This property is valid only for the SQL Server database engine; the Yes value indicates that it mustn't applythe property in case the table is a replication receiver (it has to maintain the numbers received by replication).

    If you are interested in a more in-depth look at the use of this property, refer to the GeneXus Help section.

  • 7/31/2019 01 Rules GXXEv2Course(Deepening)

    9/12

    Update

    OBJECTIVE: It enables you to update attributes of the extended table (inferred) in a transaction's form (win/web).

    SYNTAX: Update( att1[, atti]);

    WHERE:atti:is an attribute that belongs to an extended table of one of the base tables associated to the transaction.

    FUNCTIONALITY: In a transaction, all the attributes that belong to any of the base tables associated to the transaction

    are accepted by default, and those which belong to the extended table but not to the base table are inferred, andtherefore not accepted.But if you want any such inferred attributes to be accepted, so that the user can modify their value from the form, youcan use the Update rule.

    EXAMPLE:

    InvoiceId*

    InvoiceDate

    CustomerId

    CustomerName

    CustomerId*

    CustomerName

    update(CustomerName);

  • 7/31/2019 01 Rules GXXEv2Course(Deepening)

    10/12

    In what level of a transaction will the rules defined in the transaction be executed?

    Most of the time it will not be necessary to explicitly add in the definition of the rules the level of thetransaction in which you want the rules to be triggered, as the attributes involved in the rules tellGeneXus what level to execute them in.

    For example, if a rule only references attributes of the first level of the transaction where it is defined (either

    in the rule itself or in the triggering condition), GeneXus will understand that the rule is associatedto thefirst level of the transaction.

    Similarly, if a rule only references attributes of the second level of the transaction where it is defined (eitherin the rule itself or in the triggering condition), GeneXus will understand that the rule is associatedto thesecond level of the transaction.

    In the case of rules that reference attributes in more than one level, GeneXus will understand that therule is associated to the last level of the attributes involved, as only in the last level will it have thevalues of all the attributes involved.

    Some specific examples are provided below:

    1) If the following rule is defined in the "Invoice" transaction:Default(InvoiceDate, &today);

    since the only attribute mentioned in the rule is InvoiceDate, and that is an attribute of the first level of thetransaction, GeneXus will determine that it is a rule associatedto the first level.

    2) If the following rule is defined in the "Invoice" transaction:

    subtract( InvoiceDetailQuantity, ProductStock);

    since the two attributes mentioned in this rule are in the second level of the transaction, GeneXus willdetermine that it is a rule associated to the second level.

  • 7/31/2019 01 Rules GXXEv2Course(Deepening)

    11/12

    3) If the following rule is defined in the "Invoice" transaction:

    InvoiceDetailDiscount= InvoiceDetailAmount * CustomerDiscountPercentage/100;

    as InvoiceDetailDiscount(the discount corresponding to a line) is an attribute that belongs to the second level of theInvoice transaction, and CustomerDiscountPercentage (the discount percentage granted to a customer) is anattribute declared in the first level of the Invoice transaction, GeneXus will determine that it is a rule associatedtothe second level of the transaction

    When we say that a rule is associated to a certain level, it means that the rule will be executed for every instanceone works with in that level (if the rule triggering condition is met, naturally).

    In the first example we saw, the Default(InvoiceDate, &today) rule is a rule associated to the first level of the"Invoice" transaction. This means that it will be executed for every invoice header that is inserted through the firstlevel of the Invoice transaction (a characteristic of the Default rule is that it is triggered only when the executionmode is Insert).

    In the second example we saw, the subtract(InvoiceDetailQuantity, ProductStock) rule is a rule associated to thesecond level of the Invoice transaction. This means that it will be executed for the entire invoice line that is added,updated or deleted through the second level of the Invoice transaction.

    In the case of the third example, the rule:InvoiceDetailDiscount= InvoiceDetailAmount * CustomerDiscountPercentage/100is a rule associatedto the secondlevel of the Invoice transaction. Thus, this rule will be executed for the entire invoice line that is added, updated ordeleted through the second level of the Invoice transaction.

    In sum, as can be gathered from the explanation above, for every invoice one works with in an Invoice transaction:-for the header: the rules associatedto the first level will be executed

    - for each line: the rules associatedto the second level will be executed

    It is important to bear in mind that as a general rule GeneXus will always determine that a rule be triggered at thefirst opportunity in which it can be triggered, that is, upon having all the data it needs. And only in certain casesin which it is required, will the same rule be triggered again at a later stage.

    What triggering level will be associated by default to a rule in which no attributes are referenced?

    When there are no attributes involved in a rule, the level associatedby default to that rule will be the first level.

    For example, the following rule defined in the "Invoice" transaction:

    Error(Invoices cannot be deleted) if Delete;

    has no attributes involved, therefore, the level associatedby default to the rule will be the first level.

    When do you have to specifically indicate the triggering level for a rule?

    There is an optional clause called Level that allows you to modify the default level for triggering a rule, changing it toa later level.

    That is, if for example a rule is executed by default in the first level of a transaction and you want it to be executed inthe second level, you will have to add the Level component to the rule, followed by an attribute or set of attributes ofthe second level. This will execute the rule for each of the instances corresponding to the lines, and not for theinstance corresponding to the header, as was the default behavior.

    For example, if we define the following rule in the "Invoice" transaction:

    msg(The date on the invoice is greater than the current date) ifInvoiceDate> &Today;

    by default this rule will be associatedto the first level of the transaction, as the only attribute referenced in the rule isin the first level of the transaction. If for some reason we want the rule to be executed for each of the instancescorresponding to the lines instead of it being executed for the instance corresponding to the header, in the definitionof the rule we have to add the Level clause followed by one or several second level attributes:

    msg(The date on the invoice is greater than the current date) ifInvoiceDate>&TodayLevelInvoiceDetailAmount;

  • 7/31/2019 01 Rules GXXEv2Course(Deepening)

    12/12

    Adding the Level clause to a rule only makes sense if it is followed by the attributes of a level subsequent to the

    level of the attributes involved in the definition of the rule itself.

    In the next example, the fact that we added the Level clause to the rule contributes no additional information to that

    already provided by the attribute involved in the definition of the rule itself:

    msg(The date on the invoice is greater than the current date)ifInvoiceDate> &TodayLevelCustomerId;

    It's easy to see that the InvoiceDateattribute is already telling GeneXus that it is a rule associatedto the first level,

    so what the Level clause in the example is indicating does not contribute any additional information and thereforethere is no reason to add it.

    Lastly, in this next example:

    InvoiceDetailDiscount= InvoiceDetailAmount * CustomerDiscountPercentage/100LevelInvoiceDate;

    although the Level clause was included in the definition of the rule, as the attribute following the clause is of a higher

    level than that of the attributes referenced in the rule, the Level clause defined will not provide any useful informationin this case either. That is, when the attributes involved in a rule are of the second level, it is not possible for the rule

    to be executed in the first level, as the first level lacks the information of the lower level(s) (besides there being N

    instances for the lower level(s)). So the rule will still be associated to the second level of the Invoice transaction,

    with no useful information having been provided by the Level clause in this example.

    In sum, it only makes sense to add the Level clause when you want to change the default triggering level of a rule toa later level.

    How can we condition rules so that they are executed in a given mode?

    GeneXus provides the following Boolean functions to include them in the triggering condition of the rules with theaim of limiting their execution specifically to certain possible modes:

    Insert

    Update

    Delete

    Examples of use(all the rules correspond to the Invoice transaction)

    1) Noaccept( InvoiceDate) if Update;

    If you're modifying an invoice (Update mode), you will not be allowed to change the date. If a rule is defined without

    the triggering condition specified above, the InvoiceDateattribute will be disabled in every execution mode.

    2) Error( Invoices cannot be deleted ) if Delete;

    If the user tries to delete an invoice, the error preventing the deletion will be triggered. As there are no attributes

    involved in the rule, the level associated by default to the rule will be the first level.

    3) Error( Invoice lines cannot be deleted ) if Delete LevelInvoiceDetailQuantity;

    If the user tries to delete an invoice line, the error preventing the deletion will be triggered. Note that the Level clause has

    been specified in the rule followed by an attribute of the second level of the Invoice transaction, to indicate that the

    rule must be associated to the second level of the transaction.