Options

Validating a field without causing a runtime error

PevansPevans Member Posts: 18
So, my ISUser field "Location" has a TableRelation to the table "Location".

Basically, what I would like to do is this:
IF NOT VALIDATE(ISuser.Location, 'asdf') THEN
  EXIT('Invalid location');

The problem is VALIDATE does not have a return value, and instead causes a runtime error (which is impossible to catch in Navision from what I gather).

I guess I could go:
IF NOT location.GET('asdf') THEN
  EXIT ('Invalid location')
ELSE 
  ISuser.Location := 'asdf';

But this solution requires a variable for all fields I want to check for valid values, and there are quite alot. It seems to me like there might be an easier way. Any suggestions?

Answers

  • krikikriki Member, Moderator Posts: 9,120
    It is enough to give a value to the TableRelation-property of a field and Navision takes care of it. No need to put some code.
    Regards,Alain Krikilion
    No PM,please use the forum. || May the <SOLVED>-attribute be in your title!


  • PevansPevans Member Posts: 18
    First off, thanks for your reply :)

    To my knowledge, Navision only checks the TableRelation property when you call the VALIDATE function.

    You can, for example, insert the following:
    cust.Location := 'invalidLocation';
    cust.MODIFY; // TRUE or FALSE is irrelevant here
    

    and end up with an invalid value in the location field - even though this field has a TableRelation property (With ValidateTableRelation set to Yes).

    So my question of how to validate a value for a field without causing a runtime error upon an invalid entry remains. Using GET first works, but only when the field is a key.
  • krikikriki Member, Moderator Posts: 9,120
    Pevans wrote:
    So my question of how to validate a value for a field without causing a runtime error upon an invalid entry remains. Using GET first works, but only when the field is a key.
    Correct. In the other case (lets assume the code is not the primary key in the location table):

    recLocation.RESET;
    recLocation.SETCURRENTKEY("the best key you can find");
    recLocation.SETRANGE(Code,cust.Location);
    // optional other filters
    IF recLocation.FIND('-') THEN
    MESSAGE(' :D ')
    ELSE
    MESSAGE(' :cry: ');
    Regards,Alain Krikilion
    No PM,please use the forum. || May the <SOLVED>-attribute be in your title!


  • PevansPevans Member Posts: 18
    Yeah and if you call the OnValidate() trigger you basically manually do everything the VALIDATE function does. I was just wondering if there was an easier way. (The easiest way would of course be for VALIDATE to return a Bool, but what can you do :| )
  • DenSterDenSter Member Posts: 8,307
    You can do the validating in a codeunit and call the codeunit from your process. A codeunit DOES have a return value (a boolean) that returns TRUE if it ran successfully, and FALSE if it encountered an error. It will not actually error out if you check the codeunit's return value.
  • PevansPevans Member Posts: 18
    That is indeed a possibility.

    The problem (and the reason I am going on about this) is that I have many fields I want to validate, and I want a specific error message for each of them. This means I would need one codeunit per field to validate, and that doesn't seem like a good option to me.

    My apologies for not being more specific about the number of fields and the specific error messages.

    Maybe I could go with a middle-way solution and use manual checks (using GET or whatever) with simple key tables, and write codeunits for the fields with more complex keys. I'll see how it works out.

    Anyway, thanks for your input.
  • ta5ta5 Member Posts: 1,164
    Maybe you can use the following concept:
    1) Call a codeunit (as described) with "if codeunitxy.run..
    2) Use this codeunit for all validates
    3) In the codeunit use a global variable, which you use to set a specific text (e.g. "Error on validating field xy with value zz")
    4) Set this global variable, then use the validate
    5) in case of any error the codeunit is terminated, its return value is false
    6) use a function (eg getLastErrorText) on the codeunit to yield the LastErrorText
    7) Pray for a comprehensive error handling in future version :wink:

    Hope this may help
    Thomas
  • PevansPevans Member Posts: 18
    The problem with using Run() is that it doesn't take any input parameters. If you could get all the information you need from within the CU, then your suggestion would be great!

    However, my application is a web application where I have a XML document with field information I need to validate without causing a runtime error. Instead I need to use EXIT('Specific error message') when an error occurs.

    And since I can't pass the XML document (Automation) to a Run() function without storing the data, this option won't be optimal.
  • krikikriki Member, Moderator Posts: 9,120
    Pevans wrote:
    The problem with using Run() is that it doesn't take any input parameters. If you could get all the information you need from within the CU, then your suggestion would be great!
    It takes 1 parameter:the record.
    What I would do is this: on 1 of the fields I would put a filter that is the number of the field to be checked. In the codeunit you can get this filter and you have the record with all the values and you know which field to check.
    Regards,Alain Krikilion
    No PM,please use the forum. || May the <SOLVED>-attribute be in your title!


  • PevansPevans Member Posts: 18
    The problem is I don't need to pass a Rec to the codeunit - I need to pass an automation variable (an XML document). This variable is not stored anywhere - it is just passed to and from different codeunits.

    I suppose I could store my variable in some table and pass a Rec of that table to the codeunit, but that seems like a really messy way of doing it.
  • krikikriki Member, Moderator Posts: 9,120
    You can create a singleinstance-codeunit, pass the automation-variable to that codeunit, save it in there in a global variable of the codeunit.
    Then you run your codeunit and that codeunit can get the automation-variable stored in a global of the singleinstance-codeunit.
    Didn't try it out though.
    Regards,Alain Krikilion
    No PM,please use the forum. || May the <SOLVED>-attribute be in your title!


  • girish.joshigirish.joshi Member Posts: 407
    there is no problem here. You can pass references to automation variables between codeunits (as long as withevents = no). Just check the BizTalk codeunits for examples.

    The basic idea is you make your automation a global variable. Then you have getter and setter access functions.

    In fact, I believe they do exactly what you want to do -- passing a reference of the XMLDom.

    You do not need to use single instance codeunits -- in fact, you probably shouldn't unless you have some good reason.
  • PevansPevans Member Posts: 18
    So the result of all of this is the simple solution:
    validateCU.setXMLDoc(myXMLDoc);
    IF NOT validateCU.Run() THEN
      EXIT(validateCU.getLastErrorMsg());
    

    Now I am annoyed I didn't think of this before! :D

    Thanks to everyone for your help, really helps me in the final stages of this project.

    Setting this baby to SOLVED \:D/
  • DenSterDenSter Member Posts: 8,307
    You got it! Congratulations on a fine solution. \:D/
  • NaromiNaromi Member Posts: 21
    Hi everbody, i read what you've written before, i had almost the same problem and in the same way i write a CU to validate my record's dataport fields but when i write the if condition in this way :

    IF NOT CODEUNIT.RUN(CODEUNIT::"Sal.&Purch. Invoices",recGenJournalLine) THEN
    MESSAGE('Error during Inserting data');

    i have an error that tells me that i can call a CU only if the return value is not used, i m bored because i write the CU only for using return value.
    So what can i do, is there something missing to make it run ?? :-k
  • ta5ta5 Member Posts: 1,164
    Imho its a problem if you use "if codeunit.run" inside a transaction. Whats the exact error msg?
  • petevanspetevans Member Posts: 78
    Not sure if your first line is valid - try using ID instead CODEUNIT:"blabla".

    Or if that doesn't work try it with a CU variable instead of CODEUNIT.RUN.
    NAVN00b
  • NaromiNaromi Member Posts: 21
    thanks for your reply petevans and ta5, i ve tried to use the id and a CU variable also, but it still don't work, they tell me in the error that :
    some C/AL functions can't be used in writng transaction because (one table ore more are locked) like codeunit.run() is allowed only if the return value is not used (ok := codenit.run() is not allowed. in the table 81 properties i can't set permissions for CUs only for Tables :|
  • krikikriki Member, Moderator Posts: 9,120
    petevans wrote:
    Not sure if your first line is valid - try using ID instead CODEUNIT:"blabla".
    :evil: :evil: :evil: :evil: :evil: :evil: :evil: :evil: :evil: :evil: :evil: :evil:
    [-X [-X [-X [-X [-X [-X [-X [-X [-X
    NEVER use the ID of an object, but ALWAYS the option of the object like in CODEUNIT::"The Codeunit"!
    If you do this, you can make upgrading or searching where an object is used a lot more difficult.

    PS. don't take it personal, it is an error a lot of people make.
    Regards,Alain Krikilion
    No PM,please use the forum. || May the <SOLVED>-attribute be in your title!


  • petevanspetevans Member Posts: 78
    Agreed, and I wasn't recommending this approach - I just wasn't sure if his syntax was correct. I always use a variable.

    Sorry for the confusion! :oops:
    NAVN00b
  • ta5ta5 Member Posts: 1,164
    I guess this is a how the navision transaction work. Maybe you can try to use commit before calling the "if codeunit.run" statement, but this is probably not what you want and quite dangerous. Use commit only if you are very sure what you are doing.
    Thomas
  • NaromiNaromi Member Posts: 21
    in fact thomas, what i wanna do is what pete tried to make it before, catch if an error occur during validation of the dataport fields, so i will make same treatment, so what i ve understand that the only way to catch error is to test the CU return value, so i wonder why pete doesn't have this problem before because navision tells me that he doesn't allow using CU's return value, so how does it run for pete and not for me, do i supposed to set table's permissions for my CU, thanks for ur replies
  • petevanspetevans Member Posts: 78
    I actually never implemented this solution, but I think we all agreed that it should work in theory. I think I tested it as well, but I can't really remember.

    Your problem, however, seems to be that you are running your codeunit in the middle of a transaction. You need to make the call outside a transaction - either by placement in code, or by using COMMIT to end the transaction (not recommended).
    NAVN00b
  • NaromiNaromi Member Posts: 21
    thanks pete, in fact when i call a commit before the error dosn t occur, you say that there is another way to avoid the error by restructing code, can u tell me more about this plz
Sign In or Register to comment.