Attribute validation
This lesson introduces techniques for validating attributes by enforcing business logic on the values assigned to it. By completing this module, you will learn:
- How to set up attribute validation in your model.
- How to add custom business logic to the validation of a class attribute.
Create attribute validation
You can define attribute validation rules directly in your model. These rules validates attribute value before they can be saved. This consistently applies validation regardless of where they come from. That is, the values that arrive from a web service must validate against the same rules as values that arrive from the Console, or from a client interface.
By overriding base attributes in a subclass and applying validations to them, you can create polymorphic behavior. In this lesson, you validation for the training:EmailAddress
class, a subclass of training:Telcom
. The validation rule will ensure that any value submitted as an email address contains the “@” sign.
When you are writing your validation expression, two variables are immediately available to you: this represents the object whose attribute is being validated, and value contains the attribute.
Note
This module assume that you have carried out the steps in Test the model, which persists some data to the model. If you did not run those steps, or if you have subsequently carried out an action that erases data, such as using the Data Load Tool to reset or recreate the database, then you should rerun the code from that section in a Console before proceeding.
Simple true-false validation
In this lesson you create and test a validation statement that returns #t
(true) if the email address contains the "@" sign and #f
(false) if it does not. You use the string-match
command to test for the existence of "@". string-match
takes a string and a regular expression as its inputs, and either returns a list of the matching string and any substrings identified by the regular expression, or returns a value of #f (false)
.
Create the validation
- Open the
training:EmailAddress
class for editing. - Select the Attributes tab.
- In the Attributes list, click the Override Base Attributes button . This opens the Override Base Attributes window where you can select an existing base attribute to override.
- Select the
address
attribute, click the Add button, and click OK. - Select the
address
attribute and click the Validation tab. In the Validation area, enter the following script:
CODE(string-match value "@")
Javascript - if you set the language property for the attribute to "js"
JS#"string-match"(value, "@");
In this example, if the validation fails, the validation statement returns
#f (false)
, which triggers a generic validation error.- Save your work.
Restart your server or use the "reload all" button in the toolbar (or ALT-F5 or Project/Metadata Hotswap/Reload All).
Test the validation
To test the validation:
Open and existing or create a new scratchpad and enter the following commands:
CODE(define e (training:Person'new (: firstName "Glen") (: lastName "Connor"))) (define tp (read-instance training:TelcomType '() '(= name "Business") '())) (define telcom (training:EmailAddress'new (: entity e) (: type tp) (: name (tp'name)) (: address "glennexj.com") (: displayName "Glen Connor"))) (commit)
Javascript
JSvar e = new #"training:Person"({firstName: "Glen", lastName: "Connor"}); var tp = #"read-instance"(#"training:TelcomType", null, scm("'(= name \"Business\")"), null); var telcom = new #"training:EmailAddress"({entity: e, type: tp, name: tp.name, address: "glennexj.com", displayName: "Glen Connor"}); commit();
- Run the Server Console.
Execute the commands in the scratchpad one line at a time. After you run the
commit
command, the result should be...CODE;Cause: The address of Email Address must be within the allowed range.
Note that the validation occurs when you attempt to commit the change to the database, not when the
training:Telcom
instance is defined.
Also note that the error message used the class's caption (Email Address
), not the name of the class (training:EmailAddress
).- Stop the console.
Validation that returns a custom string
Now you refine the validation by adding script to return more information about the error.
Define the error message
To define the error message that you want returned if the validation fails:
- In the Resources layer, click the Strings tab.
- Double-click the
idsc.training.en
file to open it. - Click the Add button to add a new string.
- Specify an Id value of idsc.training.err.EmailMissingAtSymbol.
- Specify an en value of
Email addresses must contain the '@' symbol
. - Save your changes.
Update the validation routine
To update the validation routine for the attribute:
- Reopen
training:EmailAddress
class and select the address attribute. - Click the Validation tab.
In the Validation area, replace the existing Scheme statement with the following:
CODE(unless (string-match value "@") "idsc.training.err.EmailMissingAtSymbol" )
Javascript - if you set the language property for the attribute to "js"
JSunless(#"string-match"(value, "@"), "idsc.training.err.EmailMissingAtSymbol");
The validation error returns the Id of the string, which is resolved and used as the text of the validation error.
- Save your changes.
Test the error message
To test the error message:
Run the Server Console and test the validation by running the same commands:
CODE(define e (training:Person'new (: firstName "Glen") (: lastName "Connor"))) (define tp (read-instance training:TelcomType '() '(= name "Business") '())) (define telcom (training:EmailAddress'new (: entity e) (: type tp) (: name (tp'name)) (: address "glennexj.com") (: displayName "Glen Connor"))) (commit)
Javascript
JSvar e = new #"training:Person"({firstName: "Glen", lastName: "Connor"}); var tp = #"read-instance"(#"training:TelcomType", null, scm("'(= name \"Business\")"), null); var telcom = new #"training:EmailAddress"({entity: e, type: tp, name: tp.name, address: "glennexj.com", displayName: "Glen Connor"}); commit();
Among the errors that are reported in console you should see the following lines:
CODE;Cause: Email Addresses must contain the '@' symbol.
- Stop the console.
Validation that returns the problem value
Now you change the validation again so that the incorrectly formatted email is returned as part of the error message.
Update the error message
To update the error message that you want returned if the validation fails:
- In the Resources layer, click the Strings tab.
- Double-click the
idsc.training.en
file to open it. - Edit the idsc.training.err.EmailMissingAtSymbol message to read
Email addresses must contain the '@' sign. '{0}' is invalid.
'{0}' is a variable that will be replaced with the invalid email address. - Save your changes.
Update the validation routine
To update the validation routine for the attribute:
- Reopen the
training:EmailAddress
class and select the address attribute. - Click the Validation tab.
In the Validation area, replace the existing Scheme statement with the following:
SCHEME(unless (string-match value "@") (list "idsc.training.err.EmailMissingAtSymbol" value) )
Javascript - if you set the language property for the attribute to "js"
JSunless(#"string-match"(value, "@"), list("idsc.training.err.EmailMissingAtSymbol", value));
The validation error now returns a list of values to be formatted. The error message string is the first value. When the string is resolved it uses the remainder of the list to supply values for its variables. In this case the
{0}
variable is replaced with the value of the incorrect string.- Save your changes.
Test your validation
To test the validation:
- Run the Server Console.
Run the same commands:
CODE(define e (training:Person'new (: firstName "Glen") (: lastName "Connor"))) (define tp (read-instance training:TelcomType '() '(= name "Business") '())) (define telcom (training:EmailAddress'new (: entity e) (: type tp) (: name (tp'name)) (: address "glennexj.com") (: displayName "Glen Connor"))) (commit)
Javascript
JSvar e = new #"training:Person"({firstName: "Glen", lastName: "Connor"}); var tp = #"read-instance"(#"training:TelcomType", null, scm("'(= name \"Business\")"), null); var telcom = new #"training:EmailAddress"({entity: e, type: tp, name: tp.name, address: "glennexj.com", displayName: "Glen Connor"}); commit();
Among the errors that are reported in console you should now see the following line:
CODE;Cause: Email Addresses must contain the '@' symbol. 'glennexj.com' is invalid.
- Close the console.
Optional: Validation that returns more complex values
In this validation, you make use of both the value function and arguments of the function this to provide more information about the instance that is causing the error.
Update the error message
To update the error message that you want returned if the validation fails:
- In the Resources layer, click the Strings tab.
- Double-click the customized
idsc.training.en
file to open it. - Edit the idsc.training.err.EmailMissingAtSymbol message to read
Email addresses must contain the '@' symbol. The address '{0}' for the entity '{1}
{2}' is invalid.
- Save your changes.
Update the validation routine
To update the validation routine for the attribute:
- Reopen the
training:EmailAddress
class and select the address attribute. - Click the Validation tab.
In the Validation area, replace the existing script with the following:
CODE(unless (string-match value "@") (list "err.trainingEmailMissingAtSymbol" value ((this'entity)'firstName) ((this'entity)'lastName)) )
Javascript - if you set the language property for the attribute to "js"
JSunless( #"string-match"(value, "@"), list("idsc.training.err.EmailMissingAtSymbol", value, this.entity.firstName, this.entity.lastName) );
The validation error now returns a list of values to be formatted. The first value, the error message string, is resolved and uses the remainder of the list to supply values for its variables. This time, the first and last name values of the entity associated with the email instance will be included in the error message.- Save your changes.
Test the validation
To test the validation:
- Run the Server Console.
Run the same commands:
CODE(define e (training:Person'new (: firstName "Glen") (: lastName "Connor"))) (define tp (read-instance training:TelcomType '() '(= name "Business") '())) (define telcom (training:EmailAddress'new (: entity e) (: type tp) (: name (tp'name)) (: address "glennexj.com") (: displayName "Glen Connor"))) (commit)
Javascript
JSvar e = new #"training:Person"({firstName: "Glen", lastName: "Connor"}); var tp = #"read-instance"(#"training:TelcomType", null, scm("'(= name \"Business\")"), null); var telcom = new #"training:EmailAddress"({entity: e, type: tp, name: tp.name, address: "glennexj.com", displayName: "Glen Connor"}); commit();
Among the errors that are reported in console you should now see the following:
CODE;Cause: Email addresses must contain the '@' symbol. The address 'glennexj.com' for the entity 'Glen Connor' is invalid.
- Close the console.
Commit a valid instance
Complete this lesson by committing a telcom instance with a valid email address:
If you just restarted your server - no problem. But if you just fixed the script and ran it again, it will fail. This is because the old instance that has the bad email is still in memory and will continue to fail... to remove it from memory simply run (rollback) or rollback(), which is the opposite of (commit) or commit(). Then run your new fixed script.
Update the script in your scratchpad to read:
CODE(define e (training:Person'new (: firstName "Glen") (: lastName "Connor"))) (define tp (read-instance training:TelcomType '() '(= name "Business") '())) (define telcom (training:EmailAddress'new (: entity e) (: type tp) (: name (tp'name)) (: address "glen@nexj.com") (: displayName "Glen Connor"))) (commit)
Javascript
JSvar e = new #"training:Person"({firstName: "Glen", lastName: "Connor"}); var tp = #"read-instance"(#"training:TelcomType", null, scm("'(= name \"Business\")"), null); var telcom = new #"training:EmailAddress"({entity: e, type: tp, name: tp.name, address: "glennexj@nexj.com", displayName: "Glen Connor"}); commit();
- Save your changes.
Restart the Server Console and execute the updated code. The last line of the console output should indicate that the e-mail address was successfully saved:
CODE; 17:47:47,442 DEBUG [UnitOfWork] Commit completed
- Close the console.
Update the revision and publish (optional)
Only do this if you want some experience publishing a model. It will take some time. You did not make any changes to the database schema, so you do not need to make any changes to the upgrade file, dump file, or the database. There is no need to change the model version.
You did make a change to the way the model operates, so you should update the model revision number. Updating the revision number indicates that you have changed the metadata structure of the model since its last “release.”
- Click the Validate model button in the toolbar to validate the model and ensure there are no errors.
- Click the Set current model button to open the Model Library.
- With the current model selected, click Edit.
- Update the Revision field by incrementing the final digit by one.
- Click OK.
- Click Publish. The Publish Model window opens.
- Select the directory that you want to publish your model to and click Save.
- Close the Model Library.
The console view provides a record of the actions taking place as NexJ Studio publishes the model. If the publish is successful, the message
BUILD SUCCESSFUL
appears.Info
If the model contains any warnings or errors, you are asked to confirm whether you want to continue publishing. In this course you can ignore warnings, but you must resolve any errors. To disable warnings, ensure checkbox found at Window → Preferences → NexJ Studio → Disable validation warnings is checked.
Try it out
Modify the code in your scratchpad to enter valid email addresses and telephone numbers. Also, you will notice now that since training:Telcom
is an abstract base (from the previous lessons) you cannot create one of them directly.
Info
Use the rollback
library function to clear any previous transaction that has validation errors.