Using PROTOCLASS
You should view the generation of Caché class definitions using PROTOCLASS as an iterative process. You will run the utility on a subset of the attributes that you want represented in Caché. View and probably modify the resulting Caché property declarations using Studio. Run the utility on a few more of your attributes. View and modify the results. Repeat until you are done.
Here is a general outline of the process. Each step is elaborated on below.
-
Use CHECK.DICT to validate your dictionary entries. See Using CHECK.DICT.
-
Specify the desired Caché package and class name. See Controlling the Package and Class Name.
-
Run PROTOCLASS on the file to generate Caché properties for the simple attributes. Adjust and repeat as necessary. See Simple Attributes.
-
Run PROTOCLASS again and include the complex attributes. Adjust and repeat as necessary. See Complex Attributes.
-
Use the MVAUTO parameter of your Caché properties to control how they are affected by repeatedly running PROTOCLASS. See Controlling Property Generation Using MVAUTO.
-
Ultimately, it is likely that you will need to manually edit the Caché property declarations and methods generated by PROTOCLASS.
For introductory information on PROTOCLASS, see PROTOCLASS Overview and Loading PROTOCLASS.
The name “PROTOCLASS” is intended to highlight the fact you should view the Caché class definitions the utility generates as prototypes or starting points rather than finished products.
Using CHECK.DICT
Before running PROTOCLASS on your dictionary, use the CHECK.DICT utility to validate the dictionary entries that you intend to represent in your Caché class. CHECK.DICT verifies the following:
-
The validity of conversion and correlative codes. Caché is somewhat stricter than many MultiValue platforms with regard to validity of correlative and conversion codes. In addition, there may be some codes that are not supported by Caché. Any such codes that CHECK.DICT finds invalid need to be removed or fixed prior to running PROTOCLASS.
-
The existence of dictionary items referenced by itypes and correlatives in your dictionary. If such items do not exist, then PROTOCLASS cannot generate a valid Caché class.
If CHECK.DICT finds no errors, then it returns with no message:
MYACCOUNT: CHECK.DICT PERSON "NAME" "AGE" "HAIR" "PHONES" "@ID"
MYACCOUNT:
If CHECK.DICT finds a problem, it returns a helpful error message, for example
MYACCOUNT: CHECK.DICT PERSON *
MYACCOUNT: Error in compile: Malformed expression TEXT: MV$ITYPE$1 =
[7125] Self reference in itype 'TYPE
Controlling the Package and Class Name
By default, PROTOCLASS generates a Caché class with the same name as the original dictionary and places it in the MVFILE package. So, for example, the following command generates a class named MVFILE.PERSON.
MyAccount: PROTOCLASS PERSON *
There are two options for controlling the package and class names of the generated class.
-
Edit PROTOCLASS and set the value of its newClassName property to the desired value. If you include a period in the value then the left-hand side of the period will be the new class' package name.
-
Edit field 5 of the VOC entry for the dictionary.
MyAccount: ED VOC PERSON PERSON 6 lines long. ----:5 0005: MVFILE.PERSON ----:R MyPackage.Class 0005: MyPackage.Class ----:FI "PERSON" filed in file "VOC".
After this change, executing PROTOCLASS on PERSON generates a class named MyPackage.Class.
Simple Attributes
After you have ensured that the dictionary entries that you want represented in your Caché class are valid, run PROTOCLASS on the simple attributes that define the “raw data” (that is, D-type attributes or A and S types without A or F correlatives) in the dictonary. You need to verify that PROTOCLASS creates a non-calculated field corresponding to each of your simple attributes.
The following command runs PROTOCLASS on the listed D-type attributes of PERSON.
MyAccount: PROTOCLASS PERSON NAME AGE HAIR PHONE
The resulting class definition contains a property declaration for each of the attributes. Note that none of the properties are calculated. That is, their values are not based on the values of other properties.
Property Age As %String(COLLATION = "MVR", MVATTRIBUTE = 1, MVAUTO = "P",
MVNAME = "AGE", MVPROJECTED = 0, MVTYPE = "D");
Property Hair As %String(COLLATION = "Space", MVATTRIBUTE = 2, MVAUTO = "P",
MVNAME = "HAIR", MVPROJECTED = 0, MVTYPE = "D");
Property Name As %String(COLLATION = "Space", MVATTRIBUTE = 3, MVAUTO = "P",
MVNAME = "NAME", MVPROJECTED = 0, MVTYPE = "D", MVWIDTH = 25);
Property Phone As list Of %String(COLLATION = "Space", MVATTRIBUTE = 4,
MVAUTO = "P", MVNAME = "PHONE", MVPROJECTED = 0, MVTYPE = "D",
MVWIDTH = 12);
A calculated property has a SqlComputeCode attribute.
Complex Attributes
Once your Caché class contains properties that adequately represent your simple attributes, you can continue by running PROTOCLASS on your complex attributes (I-types and A or S types with A or F correlatives in attribute 8). For a complex attribute, PROTOCLASS generates two different Caché class members:
-
A calculated property. Properties of this type have no stored or in-memory values. Their values are calculated based on the values of other properties. One of the parameters of the property declaration is SqlComputeCode. This parameter identifies code (a Caché method) which calculates the value for the property.
-
A method containing the code that calculates a value for the property.
For example, suppose that PERSON contains an I-type property named ITEST. To generate add a property to your Caché class to represent ITEST use the following:
MyAccount: PROTOCLASS PERSON ITEST
PROTOCLASS creates the following property declaration. Note that the MVITYPE parameter contains the actual MultiValue code that defines the property. Note also the SqlComputeCode parameter. This parameter contains code that invokes a Caché method that calculates the value of the property.
Property Itest As %String(COLLATION = "Space", MVAUTO = "P",
MVHEADING = "TYPE-I", MVITYPE = "TYPE; @1[1,1]; IF @2=""F"" THEN ""FILE""
ELSE IF @2=""V"" THEN ""VERB"" ELSE IF @2=""K"" THEN ""KEYWORD"" ELSE IF
@2=""S"" THEN ""MACRO"" ELSE IF @1=""PA"" THEN ""PARAGRAPH"" ELSE IF @1=""PH""
THEN ""PHRASE"" ELSE ""OTHER""; TYPE:'-':@3",
MVNAME = "ITEST", MVPROJECTED = 0, MVTYPE = "I", MVWIDTH = 20)
[ Calculated, SqlComputeCode =
{Set {Itest}=##class(MVFILE.PERSON).calcItest({%%ID},{%RECORD})}, SqlComputed ];
Here is the method that PROTOCLASS generates to calculate the property's value.
/// Calculates property Itest from the raw ref, using the itype routine
/// IMPORTANT!!! See Protoclass Documentation
/// This routine should be recoded to use explicit properties rather than @Record.
ClassMethod calcItest(ItemID As %String, Item As %String) As %String [ Language = mvbasic ]
{
@ID =ItemID
@RECORD=Item
MV$ITYPE$1 = @RECORD<1>
MV$ITYPE$2 = MV$ITYPE$1[1,1]
MV$ITYPE$3 = IF MV$ITYPE$2 = "F" THEN "FILE"
ELSE IF MV$ITYPE$2 = "V" THEN "VERB"
ELSE IF MV$ITYPE$2 = "K" THEN "KEYWORD"
ELSE IF MV$ITYPE$2 = "S" THEN "MACRO"
ELSE IF MV$ITYPE$1 = "PA" THEN "PARAGRAPH"
ELSE IF MV$ITYPE$1 = "PH" THEN "PHRASE"
ELSE "OTHER"
MV$ITYPE$4 = @RECORD<1>:'-': MV$ITYPE$3
RETURN MV$ITYPE$4
}
@RECORD is a system variable. In the above method, it contains the current record as a delimited string. Notice that the automatically generated comments that precede the method definition suggest that you recode the method to use actual property names rather than the @RECORD syntax. This can dramatically simplify the method. In the example, the I-type property ITEST is calculated based on the value of TYPE. So, we can recode our method like this.
ClassMethod calcItest(TYPE As %String) As %String [ Language = mvbasic ]
{
IF TYPE="F" THEN RETURN "FILE"
ELSE IF TYPE="V" THEN RETURN "VERB"
ELSE IF TYPE="K" THEN RETURN "KEYWORD"
ELSE IF TYPE="S" THEN RETURN "MACRO"
ELSE IF TYPE="PA" THEN RETURN "PARAGRAPH"
ELSE IF TYPE="PH" THEN RETURN "PHRASE"
ELSE "OTHER"
}
We would then also need to change the SqlComputeCode in the property declaration to the following:
SqlComputeCode = {Set {Itest}=##class(MVFILE.PERSON).calcItest(TYPE)}
For more information on calculated properties in Caché, read SqlComputeCode and Calculated in the Caché Class Definition Reference.
For more information about @RECORD, read System Variables in the Caché MultiValue Basic Reference.
Controlling Property Generation Using MVAUTO
The Caché properties that PROTOCLASS generates all support the MVAUTO parameter. This parameter marks the source of the property definition and whether another property relies on it. Use it to avoid potential conflicts when the class is updated either manually or by one of the tools: PROTOCLASS, CREATE.INDEX or DELETE.INDEX.
The value of MVAUTO is a string containing one or more of the following:
Value | Meaning |
---|---|
P | Property defined by PROTOCLASS. |
I | Property is defined by or is being used by an index. |
R | Another property references this property. |
M | The property has been defined through manual intervention. None of the automatic tools will modify it. You must add the M manually. |
PROTOCLASS makes major updates to a property only if the value of MVAUTO is simply “P”.
DELETE.INDEX deletes a property only if the value of MVAUTO is simply “I”.
For more information on CREATE.INDEX and DELETE.INDEX, see MultiValue Commands in the Caché MultiValue Commands Reference.