Declarative Objectivity (DO) Language : Working With Data : Creating and Deleting Data
5 
Creating and Deleting Data
In this chapter, you’ll learn how to add new data by creating objects in a federated database. Then you’ll learn how to remove obsolete data by deleting objects from the federated database.
Note:This chapter shows how to use DO statements to create objects interactively. To populate a large data set, you can create and execute a script of DO statements to create a batch of objects.
A Word About Persistent Data
Before you start creating and deleting data, it’s helpful to review some basic concepts. Recall from Data Stored as Objects that a federated database stores data as fundamental units called persistent objects, where each such object consists of some number of named values.
Each persistent object in a federated database is based on a “blueprint” that describes the names and types of values that the object can hold. This “blueprint” is the object’s class, which is described in the federated database’s schema. The named values within the object correspond to the attributes that are defined by the class. Just as a building blueprint serves as a plan for creating new buildings, a schema class serves as a plan for creating new objects that can be stored persistently in the federated database. The class itself is the data type for the objects created from it.
The following diagram shows a persistent object that was created from a schema class called Vehicle. Each named value within the Vehicle object has the name and data type specified by a corresponding attribute in the Vehicle schema class.
Data Creation Begins With the Schema
At this point, it should be clear that to create an object in a federated database, you need to know something about that federated database’s schema:
At a minimum, you need to know the namespace-qualified name of the schema class that describes the object you want to create.
If you want to set nondefault values for any attributes, you also need to know the name and the data type of each attribute to be set.
Another characteristic to know about is whether a schema class is referenceable or embeddable. Objects of a referenceable class are stored and accessed independently of other objects in the federated database. In contrast, every object of an embeddable class is stored (embedded) as a compound data value within an enclosing object.
Most objects in a data set are referenceable, and you perform explicit operations to create and delete them.
Embedded objects are created and deleted implicitly.
Sample Schema
The examples used in this chapter assume a simple schema for modeling companies that rent vehicles to customers. Whenever a customer rents a vehicle, a new RentalContract object is created and connected to a particular Customer object and a particular Vehicle object.
Most of the classes in this schema are referenceable. Only the Address class is embeddable, and its objects serve as compound data values within Customer objects and RentalCompany objects. Assume that all of the classes are defined in a schema namespace called FleetData.
Note:The schema used in this chapter is a simplified version of the rental-fleet schema that is used in the reference topics in this documentation. (See Rental Fleet Sample Schema for the complete example.)
   
Discovering Schema Classes
You can use DO statements to discover the classes in a federated database’s schema. Even when you are already familiar with the schema, it can be useful to examine one or more classes to refresh your memory about class details.
 
To Display
Execute
The namespaces and names of the classes in the federated database’s schema.
The details of a particular schema class, including the definitions of its attributes.
SHOW CLASS className;
For example, the following statement shows the FleetData.Vehicle class:
SHOW CLASS FleetData.Vehicle;
The resulting class description includes the details that were specified when the class was added to the schema. You do not need to know every detail to create an object of the class, but having a general understanding of an attribute’s description can help you create objects of the class with nondefault values:
CLASS FleetData.Vehicle
{
  license: String { Encoding: Byte, Storage: Variable },
  available: Boolean,
  retired: Boolean,
  servRecs: List { Element: String { Encoding: UTF16, Storage: Variable}, Storage: Variable },
  rate: Real { Storage: B32 },
  doors: Integer { Encoding: Unsigned, Storage: B8 }, 
  seatingCapacity: Integer { Encoding: Unsigned, Storage: B8 },
  categoryCode: Integer { Encoding: Signed, Storage: B8 },
  currentRental: Reference { Referenced: FleetData.RentalContract },
  pastRentals: List { Element: Reference { Referenced: FleetData.RentalContract, Inverse: vehicle }, Storage: Variable}
}
For example, consider the description of the class’s doors attribute. This description indicates attribute’s logical type, which is the general type of the values that the attribute can hold. The description also includes several type-specific settings, which further refine the logical type:
From this description, we learn that the doors attribute can hold integer values, and furthermore, these values are unsigned and occupy 8 bits in storage. This means you can create a Vehicle object with a doors attribute that is set to an integer between 0 and 255, inclusive. (Of course, the number of doors for an actual vehicle will be much smaller!)
Note:The description of an attribute in a schema class is called an attribute structure. You can explore Attribute Structures to learn more about the different logical types and any settings they may have.
Creating Referenceable Objects
Most of the objects you will create in a federated database are referenceable objects, which are instances of referenceable classes. When you create a new referenceable object, the federated database automatically:
Selects a location for storing the object among any other existing objects.
Allocates space for each of the object’s attribute values.
Assigns a unique object identifier (OID) to the object. The unique identifier enables the object to be referenced, accessed, and deleted independently of any other object.
You create a referenceable object by executing a CREATE statement containing an object structure, which is an expression that describes the object being created. The CREATE statement returns the OID of the new object.
Depending on the object structure you supply, you can create a new referenceable object with:
All default values.
One or more specified values.
Complex values, such as strings or a collection of elements.
You can also create a pair of new related objects, where one object references the other.
Creating an Object With Default Attribute Values
The simplest way to create a new referenceable object is to create it with all default values. You do so by supplying an object structure that specifies the name of the schema class from which to create the new object, followed by empty curly braces, as shown in the following diagram:
Executing the following statement creates an instance of the schema class FleetData.Vehicle with all default attribute values:
CREATE FleetData.Vehicle{};
Each attribute in the resulting new Vehicle object is initialized with a built-in default value that is appropriate to the attribute’s data type. You can execute the following statement to see that the new Vehicle’s doors attribute is set to 0, which is the default value for an integer attribute:
FROM Vehicle RETURN doors;
Note:For a table of built-in default values for all data types, see Implicitly Assigning Default Values.
Of course, a Vehicle object with all default values isn’t especially useful. Such an object generally serves as a placeholder whose attribute values you can set later.
Creating an Object With Specified Attribute Values
You typically create a new referenceable object with specified values for some or all of its attributes. Doing so enables you to use those values to qualify the objects in subsequent queries.
You create an object with specified values by supplying an object structure that contains one or more assignment expressions. Each assignment expression includes the name of a particular attribute, followed by a colon and an expression that returns the value to be assigned. Within an assignment expression, the data type of the value expression must be compatible with the data type of the attribute. (Remember, you can obtain information about the data types of the attributes in a class by executing SHOW CLASS, as described in Discovering Schema Classes.)
For example, the following diagram shows an object structure with an assignment expression for setting the doors attribute of a Vehicle object. Recall from Discovering Schema Classes that doors is an unsigned integer attribute, so the value expression must evaluate to a positive whole number such as 4.
You can set multiple attributes in a new object by including multiple comma-separated assignment expressions in the object structure. Any assignment expression you omit causes the corresponding attribute to be set to a built-in default value.
For example, you might want to create a new Vehicle object with specified values for its available, rate, and doors attributes. Executing the following statement creates such a Vehicle:
CREATE FleetData.Vehicle{doors : 4, available : true, rate : 63.50};
Notice the different literal expressions (4, true, 63.50), which correspond to the different logical types of the attributes (Integer, Boolean, and Real). You typically use a literal expression to specify the value to be assigned, although it is possible to provide any kind of expression that returns a value of the required type.
Creating Objects With Specified Strings
When you create a new object that has an attribute for holding a string, you can include an assignment expression to specify a value for that attribute, as described in Creating an Object With Specified Attribute Values. However, as you compose the assignment expression, you should verify that the string value you specify is compatible with all of the attribute’s settings.
For example, you might want to create a new Vehicle object with a specified value for its license attribute. Recall from Discovering Schema Classes that the license attribute is of logical type String, and has the settings shown in the following excerpt from the SHOW CLASS output:
These settings can constrain the string value you specify:
The Encoding setting may affect the range of characters in the string value you specify. Because the license attribute uses the Byte encoding, its string values may contain only characters in the Latin-1 character set.
The Storage setting may affect the number of characters in the string value you specify. Because the license attribute has Variable storage, its string values can be of any length. (If the storage were Fixed, however, you would need to limit the number of characters.)
Executing the following statement creates a Vehicle with the specified license string. This statement succeeds because the specified string literal is compatible with the license attribute’s settings:
CREATE FleetData.Vehicle{license : '123ABC'};
Note:See String Tokens for details about specifying string values.
Creating Objects With Specified Collections
When you create a new object that has an attribute for holding a collection, you can include an assignment expression to specify a value for that attribute, as described in Creating an Object With Specified Attribute Values. You specify a value for such an attribute by supplying a collection structure, which is a bit more complex than the literal expressions we’ve seen for other types of attributes. A collection structure is a specially formatted expression that specifies one or more elements for one of the three supported types of collection—a list, a set, or a map.
As you compose a collection structure for a collection attribute, it is helpful to review the attribute’s settings to find out:
The type of collection that the attribute will hold (list, set, or map).
The type of values you can specify as the collection’s elements.
The number of elements you can specify, if that number is fixed.
For example, say you want to create a new Vehicle object with a specified value for its servRecs attribute, which models a collection of service-record summaries for a vehicle. Let’s review the information that SHOW CLASS displays for servRecs, as seen in Discovering Schema Classes. That information is reformatted here to make it a bit easier to read:
The logical type of the servRecs attribute (List) tells us that the attribute will hold a list, which is a collection of ordered elements that may include duplicates. (The ordering of elements is determined by the order in which they are added to the list.) The settings for the servRecs attribute further describe the list:
The Element setting describes the type of values that a servRecs list will accept as elements. The nested logical type String and its settings indicate that such values are variable-length strings of Unicode characters.
The Storage setting affects the number of values that a servRecs list will accept as elements. Because the servRecs attribute has Variable storage, you can specify any number of elements. (A list with FixedSize storage must have a specific number of elements.)
The following diagram shows a collection structure that is suitable for initializing the servRecs collection attribute. Notice the List keyword and the curly braces enclosing the comma-separated string values:
The following statement uses this collection structure to create a new Vehicle object whose initial servRecs list consists of the two specified strings:
CREATE FleetData.Vehicle{servRecs : LIST{'first inspection', 'changed oil'}};
Note:See Collection Structures for examples of collection structures that specify elements for sets and maps.
Stylistic Hint: Simplify Statements with LET
DO statements such as those shown in the previous section can become difficult to read if you need to specify values that are quite lengthy or complex.
For example, say you want to create a new Vehicle object to represent a used car that already has a fairly long service record. The following statement accomplishes this, but the lengthy collection structure assigned to the servRecs attribute makes it a bit harder to see the values assigned to the other attributes:
CREATE FleetData.Vehicle{license: '345XYZ', servRecs : LIST{'first inspection', 'changed oil', 'changed oil filter', 'lubricated chassis', 'changed air filter', 'flushed cooling system', 'added antifreeze', 'wheel alignment', 'rotated tires', 'adjusted brakes'}, available : true};
As a stylistic alternative, you can execute a LET statement to assign the collection structure to a name such as records, and then use that named value as a parameter in the next statement, which creates the Vehicle object:
LET records = LIST{'first inspection', 'changed oil', 'changed oil filter', 'lubricated chassis', 'changed air filter', 'flushed cooling system', 'added antifreeze', 'wheel alignment', 'rotated tires', 'adjusted brakes'};
 
CREATE FleetData.Vehicle{license: '345XYZ', servRecs : $records, available : true};
In general, you can use LET to define a parameter by assigning a value of any type to a name of your choosing, and then use that parameter with a dollar sign ($) prefix as an expression in subsequent statements. Parameters have many uses in addition to making complex statements more readable; we’ll see one of them in Creating a Pair of Related Referenceable Objects.
Deleting Referenceable Objects
You remove obsolete data from a federated database by deleting one or more referenceable objects (instances of a referenceable class). Deleting a referenceable object:
Permanently discards the object’s values, including any embedded objects it may hold.
Releases the object’s storage space.
Frees up the object identifier (OID) of the object, which enables that OID to be subsequently reused for some other newly created object.
You delete referenceable objects with DO by executing a DELETE statement that specifies (at a minimum) the schema class of the objects to be deleted. You can optionally include a RETURN clause to produce a concise report listing the deleted objects. (Without the RETURN clause, you’ll see all of the attribute values of every deleted object.)
Depending on the clauses you include in the statement, you can:
Delete the qualifying referenceable objects of the specified schema class.
Delete a particular referenceable object of the specified schema class.
Delete all referenceable objects of the specified schema class.
Note:You delete objects of one class at a time. To delete objects of multiple schema classes, you must execute additional DELETE statements.
Note:If you want to delete an object that is referenced by another object, you may need to remove the reference before performing the deletion. See Deleting Related Objects.
Deleting Objects With Qualifying Values
You can delete the objects of a referenceable schema class that have attribute values that meet some specific criteria. To do so, you execute a DELETE statement that contains:
A DELETE clause that specifies the namespace-qualified name of the schema class of the unwanted objects.
A WHERE clause that filters the objects of the specified class, and returns just the objects to be deleted.
An optional RETURN clause.
For example, the statement in the following diagram deletes just the objects that represent 4-door vehicles:
The number of objects that are deleted depends on how many objects satisfy the predicate expression in the WHERE clause. If the federated database has only one Vehicle object with 4 doors, the statement in the diagram will delete just a single object. In contrast, if every Vehicle object has 4 doors, then this statement deletes all objects of the Vehicle class.
You can narrow the set of objects to be deleted by combining predicate expressions. For example, the following statement deletes only 4-door vehicles that are unavailable:
DELETE FleetData.Vehicle WHERE doors == 4 AND available == false;
Note:If no objects satisfy the WHERE clause, the statement simply returns empty curly braces to indicate that no objects were deleted.
Deleting a Particular Object of a Schema Class
If you know the object identifier of a particular object you want to delete, you can use that identifier to qualify the object. To do so, you supply a WHERE clause with a predicate expression that uses the system value $$ID to compare each object’s identifier to a specified literal.
For example, the following statement deletes just the Vehicle object whose object identifier is 3-3-1-4:
DELETE FleetData.Vehicle WHERE $$ID == 3-3-1-4;
Deleting All Objects of a Schema Class
You can delete all objects of a referenceable schema class. You normally do this only when preparing to drop the class from the schema.
To delete all objects of a schema class, you execute a DELETE statement that contains:
A DELETE clause that specifies the namespace-qualified name of the schema class of the unwanted objects.
An optional RETURN clause.
Notice that you do not include a WHERE clause for filtering the objects of that class.
For example, the following statement deletes every Vehicle object in the federated database:
DELETE FleetData.Vehicle;
A Closer Look at Relationships
So far, we’ve seen how to create and delete individual referenceable objects. In practice, however, you rarely maintain objects in isolation, but form graphs of objects that are related to each other. One object is related to another when it holds a reference to the other object. A reference is a value that encapsulates the object identifier (OID) of the referenced object, which must be an instance of a referenceable class.
In this section, we’ll take a closer look at how relationships are modelled in a federated database. Then, in Creating and Deleting Related Objects, we’ll see how to create small graphs of related objects in a single operation.
Unidirectional Relationships
In the simplest case, two objects are unidirectionally related when one object holds a reference to the other. A unidirectional reference supports one-way traversal from the referencing object to the referenced object.
For example, the following diagram shows objects of two classes in our sample schema, namely, Customer and RentalContract. The Customer object has a currentRental attribute whose value is a unidirectional reference to the RentalContract object. This means you can query for a Customer and use it to find its related RentalContract, but not vice versa.
Bidirectional Relationships
Now let’s look at a bidirectional relationship between objects of the same two classes. The Customer object has a rentals attribute that holds a list of bidirectional references to RentalContract objects. Each of the referenced RentalContract objects has a customer attribute whose value is a bidirectional reference that points back to the Customer object. The rentals and customer attributes are inverses of each other because they hold coordinated pairs of bidirectional references. This means that you can query a Customer to find its RentalContracts, and you can query each RentalContract to find the associated Customer.
 
To-One and To-Many Relationships
At this point, we’ve seen two relationships between Customer and RentalContract objects, where one relationship is unidirectional and the other is bidirectional. These relationships also differ in terms of the number of objects that are referenced.
Take the relationship that is modelled by a Customer’s currentRental attribute. This attribute is a reference attribute, whose value is a single reference. Accordingly, this attribute models a to-one relationship, which means that a given Customer object can be related to at most one RentalContract through that attribute.
The bidirectional relationship between Customer and RentalContract is a bit more complex, because it has two separate ends, each modelled by a different attribute. The end of the relationship modelled by the Customer’s rentals attribute is to-many, because rentals is a collection attribute that holds a list of references as its value. The other end of the relationship is to-one, because it is modelled by the RentalContract’s customer attribute, which a reference attribute. Together, these two ends produce a one-to-many relationship, so that:
A given Customer object can be related to any number of RentalContract objects through the rentals attribute.
A given RentalContract object can be related to at most one Customer object through the customer attribute.
A federated database’s schema supports relationships with any combination of directionality (unidirectional vs. bidirectional) and cardinality (to-one vs. to-many).
Relationships in SHOW CLASS Output
It’s helpful to be able to recognize how SHOW CLASS describes the attributes that model relationships.
First, look at currentRental in the Customer class. This attribute models the unidirectional, to-one relationship, and is a simple reference attribute. Its logical type is Reference, and it has a specified referenced class (FleetData.RentalContract).
Now look at the description of rentals in the Customer class. This attribute models the to-many end of the bidirectional relationship. As a collection attribute, its overall logical type is List, with settings that describe the type and number of its elements. These elements, like the values of currentRental, are references to objects of the referenced class FleetData.RentalContract. But notice that the rentals elements are bidirectional references, because they have an Inverse setting, which specifies the inverse attribute customer within the referenced class. (A unidirectional reference does not specify an inverse.)
When we use SHOW CLASS to examine the RentalContract class, we see that its customer attribute has an Inverse setting that completes the bidirectional relationship with the Customer class’s rentals attribute:
Creating and Deleting Related Objects
You rarely maintain objects in isolation, but rather form graphs of objects that are related to each other, as we saw in A Closer Look at Relationships. In this section, we’ll see how to:
Create a pair of related objects in a single operation.
Create a group of new objects in a one-to-many relationship, all in a single operation.
Create a new object that is related to one or more existing objects.
We’ll also see what happens when you delete an object that is referenced by another object.
Note:An alternative technique is to create objects individually, and then use an UPDATE statement with a SET clause to set references between them in a separate update operation.
Creating a Pair of Related Referenceable Objects
You can create a pair of related referenceable objects in a single operation. That is, whenever you create a new object that has a reference attribute, you can also create the object to be referenced, all in the same DO statement.
For example, say you want to create a new Customer object that references a new RentalContract through the to-one relationship modeled by the Customer’s currentRental attribute. To do this, you execute a CREATE statement that has another CREATE statement nested within it. (The nested statement does not have a semicolon.) The top-level statement creates the Customer object, and the nested CREATE statement creates the referenced RentalContract:
CREATE FleetData.Customer{
    lastName : 'Mertz', 
    currentRental : CREATE FleetData.RentalContract{trackingNumber : 15} 
};
The object structure describing the new Customer assigns values to two attributes:
The string attribute lastName, which is set using a string literal as described in Creating Objects With Specified Strings.
The reference attribute currentRental, which is set to the value returned by the nested CREATE statement. This statement not only creates a new RentalContract object with the specified trackingNumber, but also returns a reference to that object.
Note:A CREATE statement can become a bit hard to read if it encloses a CREATE statement that creates an object with a large number of complex or lengthy attribute values. You can improve readability by using a parameter to replace the nested CREATE statement.
For example, the following LET statement defines a parameter newRC and assigns the OID of a newly RentalContract object to it. Then the parameter is used in the CREATE statement to specify the value of the currentRental reference attribute:
LET newRC = CREATE FleetData.RentalContract{trackingNumber : 15};
CREATE FleetData.Customer{lastName : 'Mertz', currentRental : $newRC};
This example is similar to the one in Stylistic Hint: Simplify Statements with LET, except now the value being assigned is the result of a CREATE statement, instead of a collection structure or other literal value. For more details, you can read Using the Result of a CREATE Statement.
Creating a Group of Related Referenceable Objects
You can create a new referenceable object that is related to multiple new objects through a to-many relationship. Put another way: whenever you create a new object that has an attribute for holding a collection of references, you can also create some or all of the objects to be referenced.
For example, say you want to create a new Customer object that references multiple new RentalContract objects through the to-many relationship modeled by the rentals attribute. To do this, you execute a CREATE statement such as the following, in which the top-level CREATE statement creates the Customer object, and two nested CREATE statements create the referenced RentalContracts:
CREATE FleetData.Customer{
    lastName : 'Suarez', 
    rentals : LIST{
        CREATE FleetData.RentalContract{trackingNumber : 25},
        CREATE FleetData.RentalContract{trackingNumber : 35}
    }
};
Because rentals is a list attribute, you assign a collection structure to it, as described in Creating Objects With Specified Collections. The two CREATE statements are nested within the collection structure. If you query for the new Customer object, you’ll see that its rentals list contains two elements, which are the RentalContract references returned by the two nested CREATE statements.
Recall that the rentals attribute is part of a bidirectional relationship. Whenever you set one end of a bidirectional relationship, the other end (the inverse) is automatically set as well. If you query for one of the new RentalContract objects, you’ll see that it was created with its customer attribute referencing the new Customer object, even though no explicit assignment was made to that attribute.
Creating an Object that References One or More Existing Objects
Sometimes it is useful to create a new object that holds a reference to an existing referenceable object. If you know the object identifier (OID) of the existing object, you can specify that OID within an assignment expression when you create the new object. Or, the new object may need to hold a collection of references to existing referenceable objects. If you know the OIDs of these objects, you can specify those OIDs as elements within a collection structure.
For example, assume that Mr. Mertz is a repeat customer who wants to enter into a new rental contract. He is represented by an existing Customer object whose OID is 3-3-1-8. The following statement creates a new RentalContract whose customer attribute references the relevant Customer object.
CREATE FleetData.RentalContract{trackingNumber : 55, pickup : 2017/03/17, dropoff : 2017/03/28, customer : 3-3-1-8};
Note:You typically obtain the OID of an existing object by examining the result of a prior query. If that is not convenient—for example, because you are writing a script consisting of DO statements to be processed from a file—you can use a LET statement to assign the query result to a parameter, and then use an expression to extract the OID from the parameter. See Obtaining a Reference to an Existing Object From a Parameter.
When you specify an OID for a reference attribute, you must make sure the class of the referenced object is compatible with the referenced class of the attribute. In the above example, this means the specified OID must reference an object of class Customer. Or, if Customer had a subclass, the specified OID could reference an object of the subclass. An error is returned if you specify the OID of an object that is not of the expected referenced class.
Deleting Related Objects
When you delete a referenceable object, you need to be aware of the effect this operation may have on any related objects. The effect is different depending on whether the relationship is bidirectional or unidirectional.
A bidirectional relationship automatically manages the referential integrity of the related objects. That is, if two objects are linked through a bidirectional relationship, then deleting either of these objects automatically deletes the other object’s reference to it. Only the reference is deleted—the other object remains in the federated database. Note that:
If the reference is held in a reference attribute, that attribute is automatically cleared (set to null).
If the reference is an element of a collection, that reference is simply removed from the collection.
For example, recall that a Customer object is bidirectionally related to several RentalContract objects through its rentals attribute. If you delete the Customer object, the operation automatically clears the customer attribute of each RentalContract object. If, instead, you delete one of the RentalContract objects, the operation automatically removes the corresponding reference from the Customer’s list of references.
A unidirectional relationship does not manage referential integrity for you. If one object is linked to another by a unidirectional relationship, then there are two cases to consider:
If you delete the referencing object, there is no effect on the referenced object.
If you delete the referenced object, the delete operation will leave a “dangling” reference behind in the referencing object. This reference is invalid, because it no longer points to an existing object.
For example, recall that a Customer object is unidirectionally related to a RentalContract object through its currentRental attribute. Deleting the Customer object has no effect on the RentalContract object. If, instead, you delete the RentalContract object, the corresponding reference remains in the Customer object’s currentRental attribute, even though it no longer points to any existing RentalContract.
Note:Before you delete an object, you should first update any object that holds a unidirectional reference to it. You can use an UPDATE statement with a CLEAR clause to clear any reference attribute that holds a unidirectional reference. You can use an UPDATE statement with a REMOVE clause to remove each unidirectional reference from a collection.
Creating and Deleting Embedded Objects
Some of the objects you will create and delete in a federated database are embedded objects, which are instances of embeddable classes. Storage space for an embedded object is always allocated within the storage space of some other enclosing object.
For example, the following diagram shows an Address object that is embedded within an enclosing RentalCompany object. The Address object is an instance of the embeddable class Address.
The object enclosing an embedded object is an instance of a schema class that defines an embedded-object attribute. In our example, the RentalCompany object is the enclosing object, because its class defines an embedded-object attribute corporateAddress for holding an Address object.
The enclosing object’s class is typically referenceable, as in our example, but that is not required. You can define schema classes so that embedded objects are stored within other embedded objects. Ultimately, however, every embedded object is either directly or indirectly stored within a referenceable object, which is its enclosing referenceable object.
You can think of an embedded object as a compound data value within its enclosing referenceable object. As such, an embedded object does not have its own assigned object identifier, and so cannot be referenced or otherwise accessed independently of the enclosing referenceable object. Furthermore:
You create an embedded object implicitly whenever you create its enclosing referenceable object.
You delete an embedded object implicitly whenever you delete its enclosing referenceable object.
Creating an Embedded Object
You create an embedded object implicitly whenever you create a referenceable object that has an embedded-object attribute. You create the referenceable object in the usual way—by executing a CREATE statement with an object structure specifying the referenceable class. The statement returns the new referenceable object, which encloses the new, implicitly created embedded object. For example, the referenceable class RentalCompany defines an attribute called corporateAddress for holding an object of the embeddable class Address. Whenever you create a new RentalCompany object, a new instance of Address is created implicitly as the value of the corporateAddress attribute.
You can optionally specify any number of attribute values for a new embedded object. To do this, you include a nested object structure as the value of the embedded-object attribute. Each assignment expression within the nested object structure must assign a value of the correct type to an attribute of the embedded object. (You can obtain information about the data types of the attributes in an embeddable class by executing SHOW CLASS, as described in Discovering Schema Classes.)
For example, the following diagram shows a CREATE statement that creates a new referenceable RentalCompany, and provides a nested object structure to specify the state attribute of the new embedded Address:
Here’s a more interesting example, which assigns values to attributes of both the new RentalCompany object and the new embedded Address object. (Every omitted attribute is assigned a default value that can be changed later.)
CREATE RentalCompany{name: 'Acme', corporateAddress: Address{city: 'San Jose', state: 'CA'}};
DO supports an alternative syntax for setting the attributes of an embedded object. Instead of using a nested object structure, you can treat the attributes of the embedded object as reachable attributes of the enclosing referenceable object. For example, the following statement has just a single object structure (for the RentalCompany), and uses the expressions corporateAddress.city and corporateAddress.state to set the embedded Address object’s city and state attributes:
CREATE RentalCompany{name: 'Acme', corporateAddress.city: 'San Jose', corporateAddress.state: 'CA'};
Deleting an Embedded Object
You delete an embedded object implicitly whenever you delete a referenceable object that has an embedded-object attribute. You delete the referenceable object in the usual way—by executing a statement that includes a DELETE clause and specifies the referenceable object’s class. Deleting a referenceable object discards all of its attribute values, including those of any objects it embeds.
Note:You cannot delete an embedded object without deleting its enclosing referenceable object, although you can use an UPDATE statement with a CLEAR clause clause to clear the embedded object’s attribute values to set them to their respective defaults.