Using Caché Objects
Defining and Using Object-Valued Properties
|
|
This chapter describes how to define and use object-valued properties, including
serial object properties. It discusses the following topics:
When viewing this book online, use the
preface of this book to quickly find other topics.
Property PropName as Classname;
Where
Classname is the name of an
object class other than a collection or a stream. (Collection properties and stream properties are special cases discussed in earlier chapters.) In general,
Classname is either a registered object class, a persistent class, or a serial class (see the
next section).
To define such a property, define the class to which the property refers and then add the property.
Class MyApp.CurrencyOrder [ NoExtent ]
{
Property Payment as MyApp.CreditCard (CLASSNAME=1);
//other class members
}
Note that SQL arrow syntax does not work in this scenario. (You can instead use a suitable JOIN.)
Important:
Do not specify
CLASSNAME =1 for a property whose type is a serial class. This usage is not supported.
Serial classes extend
%SerialObject. The purpose of such classes is to serve as a property in another object class. The values in a serial object are serialized into the parent object. Serial objects are also called embedded (or embeddable) objects. Caché handles serial object properties differently from non-serial object properties. Two of the differences are as follows:
-
It is not necessary to call
%New() to create the serial object before assigning values to properties in it.
-
If the serial object property is contained in a persistent class, the properties of the serial object are stored within the extent of the persistent class.
Later sections of this chapter show these points.
To define a serial class, simply define a class that extends
%SerialObject, and add properties and other class members as needed. The following shows an example:
Class Sample.Address Extends %SerialObject
{
/// The street address.
Property Street As %String(MAXLEN = 80);
/// The city name.
Property City As %String(MAXLEN = 80);
/// The 2-letter state abbreviation.
Property State As %String(MAXLEN = 2);
/// The 5-digit U.S. Zone Improvement Plan (ZIP) code.
Property Zip As %String(MAXLEN = 5);
}
The following table shows the possible combinations of a parent class and an object-valued property in that class:
-
Reference properties (properties based on other persistent objects)
-
Embedded object properties (properties based on serial objects)
Relationships are another kind of property that associates different persistent classes; see the chapter
Relationships. Relationships are bidirectional, unlike the properties described in this chapter.
To set an object-valued property, set that property equal to an OREF of an instance of a suitable class.
Consider the scenario where
ClassA contains a property
PropB that is based on
ClassB, where
ClassB is an object class:
Class MyApp.ClassA
{
Property PropB as MyApp.ClassB;
//additional class members
}
Suppose that
MyClassAInstance is an OREF for an instance of
ClassA. To set the value of the
PropB property for this instance, do the following:
-
If
ClassB is not a serial class, first:
-
Obtain an OREF for an instance of
ClassB.
-
Optionally set properties of this instance. You can also set them later.
-
You can skip this step if
ClassB is a serial class.
-
Optionally use cascading dot syntax to set properties of the property (that is, to set properties of
MyClassAInstance.
PropB).
set myclassBInstance=##class(MyApp.ClassB).%New()
set myClassBInstance.Prop1="abc"
set myClassBInstance.Prop2="def"
set myClassAInstance.PropB=myclassBInstance
set myClassAInstance.PropB.Prop3="ghi"
Notice that this example sets properties of the
ClassB instance directly, right after the instance is created, and later more indirectly via cascading dot syntax.
The following steps accomplish the same goal:
set myClassAInstance.PropB=##class(MyApp.ClassB).%New()
set myClassAInstance.PropB.Prop1="abc"
set myClassAInstance.PropB.Prop2="def"
set myClassAInstance.PropB.Prop3="ghi"
In contrast, if
ClassB is a serial class, you can do the following, without ever calling
%New() for
ClassB:
set myClassAInstance.PropB.Prop1="abc"
set myClassAInstance.PropB.Prop2="def"
set myClassAInstance.PropB.Prop3="ghi"
In the case where you are using persistent classes, save the containing object (that is, the instance that contains the object property). There is no need to save the object property directly, because that is saved automatically when the containing object is saved.
The following examples demonstrate these principles. Consider the following persistent classes:
Class MyApp.Customers Extends %Persistent
{
Property Name As %String;
Property HomeStreet As %String(MAXLEN = 80);
Property HomeCity As MyApp.Cities;
}
Class MyApp.Cities Extends %Persistent
{
Property City As %String(MAXLEN = 80);
Property State As %String;
Property ZIP As %String;
}
In this case, we could create an instance of
MyApp.Customers and set its properties as follows:
set customer=##class(MyApp.Customers).%New()
set customer.Name="O'Greavy,N."
set customer.HomeStreet="1234 Main Street"
set customer.HomeCity=##class(MyApp.Cities).%New()
set customer.HomeCity.City="Overton"
set customer.HomeCity.State="Any State"
set customer.HomeCity.ZIP="00000"
set status=customer.%Save()
if $$$ISERR(status) {
do $system.Status.DisplayError(status)
}
set customer=##class(MyApp.Customers).%New()
set customer.Name="Burton,J.K."
set customer.HomeStreet="17 Milk Street"
set customer.HomeCity=##class(MyApp.Cities).%OpenId(3)
set status=customer.%Save()
if $$$ISERR(status) {
do $system.Status.DisplayError(status)
}
In the following variation, we open an existing city and modify it, in the process of adding the new customer:
set customer=##class(MyApp.Customers).%New()
set customer.Name="Emerson,S."
set customer.HomeStreet="295 School Lane"
set customer.HomeCity=##class(MyApp.Cities).%OpenId(2)
set customer.HomeCity.ZIP="11111"
set status=customer.%Save()
if $$$ISERR(status) {
do $system.Status.DisplayError(status)
}
This change would of course be visible to any other customers with this home city.
A reference property is projected as a field that contains the ID portion of the OID of the referenced object. For instance, suppose a customer object has a
Rep property that refers to a
SalesRep object. If a particular customer has a sales representative with an ID of 12, then the entry in the
Rep column for that customer is also 12. Because this value matches that of the particular row of the ID column of the referenced object, you can use this value when performing any joins or other processing.
Note that within Caché SQL, you can use a special reference syntax to easily use such references, as an alternative to using a JOIN. For example:
SELECT Company->Name FROM Sample.Employee ORDER BY Company->Name
An embedded object property is projected as multiple columns in the table of the parent class. One column in the projection contains the entire object in serialized form (including all delimiters and control characters). The rest of the columns are each for one property of the object.
The name of the column for the object property is the same as that of the object property itself. The other column names are made up of the name of the object property, an underscore, and the property within the embedded object. For instance, suppose a class has a
Home property containing an embedded object of type
Address;
Home itself has properties that include
Street and
Country. The projection of the embedded object then includes the columns named
Home_Street and
Home_Country. (Note that the column names are derived from the property,
Home, and not the type,
Address.)
For example, the sample class
Sample.Person, includes a
Home property which is an embedded object of type
Sample.Address. You can use the component fields of
Home via SQL as follows:
SELECT Name, Home_City, Home_State FROM Sample.Person
WHERE Home_City %STARTSWITH 'B'
ORDER BY Home_City
Embedded objects can also include other complex forms of data:
-
-
The projection of an array is as a single, non-editable column that is part of the table.
-