Objectivity REST : Getting Started With Objectivity REST : Working with Relationships
2 
Working with Relationships
This topic will teach you about creating relationships between objects in your federated database.
In this topic you will:
Learn how relationships work.
Update your federated database to include schema with relationships.
Add various objects to the federated database using a transaction resource that supports batch processing for REST requests.
Create a unidirectional relationship from one object to another.
Create a bidirectional relationship between objects.
Understanding Relationships
In Objectivity REST, objects have relationships to other objects through references or lists of references. Relationships can be unidirectional or bidirectional depending on whether a value is set for the inverse attribute.
Let’s look at some relationships defined by the schema from the rental fleet example. In this example, there is a unidirectional relationship from the Vehicle class to the RentalContract class, and a bidirectional relationship between the RentalContract class and the Customer class.
The unidirectional relationship from Vehicle to RentalContract is supported via the currentRental attribute. This attribute can hold a reference to a single RentalContract object. The inverseAttribute value for currentRental is set to an empty string indicating that the referenced class does not have an inverse attribute pointing back to the originating class.
The relationship between the RentalContract and Customer classes is more interesting. The relationship is bidirectional, so each class has an inverseAttribute whose value is set to the name of an attribute on the other. An instance of the Customer class can have multiple associated RentalContract objects, so the rentals attribute is defined as a list of references. A list attribute has an element specification to define the elements that will comprise the list.
Adding the Complete Rental Fleet Schema
Recall that a class description for the Customer class was added in the previous topic (A Quick Tour). In this section, you will update the Customer class and add the rest of the classes for the sample at the same time. A single PUT operation on the schema resource can accomplish this.
As an aside, POST and PUT operations for the schema resource provide similar capabilities and accept the same format for representing classes. The difference is that a POST operation can only create new classes whereas a PUT operation can create new or update existing classes. With a PUT operation, you can provide additional attributes for an existing class, or you can define new classes, or both.
When adding a class description that includes a relationship, the description for the referenced class must exist either within the set of classes being added or within the existing classes of the federated database. If you try to add a class description that has a relationship to a class whose description is not accessible, you get an error.
Important: When modifying existing class descriptions of a populated federated database, be aware that data loss can result depending on the type of change; see Consequences of Schema Evolution.
To update the schema for the federated database:
1. See Schema for Rental Fleet Example and click on the download link to get a copy of the schema file (rentalFleetSchema.txt).
Alternatively, you can copy and paste the class descriptions from the topic page into a new file called rentalFleetSchema.txt.
The schema representation provides all class descriptions used by the rental fleet example including an updated version of the class description for the Customer class.
2. Use a PUT operation to add and update class descriptions:
curl -X PUT -H "Content-Type:application/json,Accept:application/json" -d @rentalFleetSchema.txt localhost:8185/v1/schema
The class numbers and URIs for all the classes are returned.
3. Verify that the Customer class was updated:
curl -X GET -H "Accept:application/json" localhost:8185/v1/schema/FleetData.Customer
Observe the updated schema for the Customer class. In particular, note the rentals attribute, which holds a list of references.
{
   "className": "FleetData.Customer",
   "classNumber": "1000000",
   "shapeNumber": "1000001",
   "isReferenceable": true,
   "isInternal": false,
   "isDeleted": false,
   "superClass": null,
   "attributes": [
     {
       "attributeName": "rewardPoints",
       "logicalType": "integer",
       "encoding": "unsigned",
       "storage": "b32"
     },
     ...
 
     {
       "attributeName": "rentals",
       "logicalType": "list",
       "storage": "variable",
       "elementSpecification": {
          "logicalType": "reference",
          "referencedClass": "FleetData.RentalContract",
          "inverseAttribute": "customer"
        }
     }
   ]
}
 
When accessed either by name or class, the class automatically gets the latest shape number.
Using a Transaction to Add Objects
You can use a transaction to submit multiple Objectivity REST requests in a batch operation. This functionality can be useful when creating objects with relationships.
Before you can create an relationship to a target object, you need its OID. In this topic, you will first use a transaction to add a set of objects without designating values for their relationships. You will then use a second transaction to set up the relationships.
Consider the following JSON body, which provides an array of Objectivity REST requests for creating objects in the federated database. Each entry in the array provides the HTTP method, the URI, and the request body. Note that the array creates a Customer object, a RentalContract object, and a Vehicle object.
The result parameter is set to keep, which instructs the Objectivity REST server to make permanent changes. (The parameter can be set to dispose otherwise.)
[
  {
    "method": "post", "uri": "/v1/object",
    "body":
      {
        "class": "FleetData.Customer",
        "attributes":
          {
            "firstName": "Jack",
            "lastName": "Green"
          }
      }, "result": "keep"
  },
  {
    "method": "post", "uri": "/v1/object",
    "body":
      {
        "class": "FleetData.RentalContract",
        "attributes":
          {
            "trackingNumber": "122"
          }
      }, "result": "keep"
  },
  {
    "method": "post", "uri": "/v1/object",
    "body":
      {
        "class": "FleetData.Vehicle",
        "attributes":
          {
            "license": "XLT5663"
          }
      }, "result": "keep"
  }
]
To create these objects:
1. Copy and paste the above JSON into a file named firstTransaction.txt in the data directory.
2. Post the transaction for processing as follows:
curl -X POST -H "Content-Type:application/json,Accept:application/json" -d @firstTransaction.txt localhost:8185/v1/transaction
The success code and the result for each operation in the transaction are returned.
[
  {
    "responseCode": 201,
    "result": {
      "__identifier__": "3-3-1-5",
      "uri": "/v1/object/3-3-1-5"
    }
  },
  {
    "responseCode": 201,
    "result": {
      ...
    }
  },
  {
    "responseCode": 201,
    "result": {
      ...
    }
  }
]
Notice that the OID 3-3-1-5 is reused for one of the new objects. (This OID was freed up when you performed the delete operation in Deleting Objects.)
Creating a Unidirectional Relationship
Recall that a Vehicle has a unidirectional relationship to a RentalContract via the currentRental attribute. In order to create the relationship, you need to update the Vehicle and set the value of currentRental to the OID for the your RentalContract, for example:
When updating an object, you use its OID in the URI, then supply attribute values in the request body; see PUT /v1/object/{oid}. With a PUT operation, you need only specify the attributes you want to change—omit other attributes (for better performance).
Assume that a Customer named Jack Green is renting the Vehicle whose license is XLT5663. A RentalContract with the tracking number of 122 will be used to encapsulate this agreement. In this exercise, you will update the chosen Vehicle to associate it with the correct RentalContract.
To add a unidirectional relationship from the Vehicle to the RentalContract:
1. Query for the RentalContract with the trackingNumber 122 and make a note of its OID.
curl -X POST -H "Content-Type:application/json,Accept:application/json" -d "{\"query\":\"FROM FleetData.RentalContract WHERE trackingNumber == 122 RETURN *;\",\"language\":\"do\"}" localhost:8185/v1/query
2. Query for the Vehicle with the license XLT5663 and make a note of its OID.
curl -X POST -H "Content-Type:application/json,Accept:application/json" -d "{\"query\":\"FROM FleetData.Vehicle WHERE license == 'XLT5663' RETURN *;\",\"language\":\"do\"}" localhost:8185/v1/query
3. Use a PUT operation on the Vehicle object to set up the relationship to the RentalContract object. If necessary, change the OIDs shown here to the actual OIDs for the RentalContract and Vehicle objects in your federated database.
curl -X PUT -H "Content-Type:application/json,Accept:application/json" -d "{\"class\":\"FleetData.Vehicle\",\"attributes\":{\"currentRental\":\"3-3-1-8\"}}" localhost:8185/v1/object/3-3-1-9
4. Confirm your change by getting the updated Vehicle object.
curl -X GET -H "Accept:application/json" localhost:8185/v1/object/3-3-1-9
You should see something similar to this.
Creating a Bidirectional Relationship
Now you are ready to create the bidirectional relationship between the Customer, Jack Green, and the RentalContract.
Before proceeding, let’s consider the schema for the Customer and RentalContract classes. A Customer has a rentals attribute that specifies a list of references to RentalContract objects, and a RentalContract object has a customer attribute that has a reference back to a single Customer object. These two attributes have inverse attributes in the schema, as follows:
{
  "name": "Customer",
  ...
  "attributes": [
    {
      "name": "rentals",
      "logicalType": "list",
      "storage": "variable",
      "elementSpecification": {
        "logicalType": "reference",
        "referencedClass":
            "FleetData.RentalContract",
        "inverseAttribute": "customer"
      }
    }
    ...
{
  "name": "RentalContract",
  ...
  "attributes": [
    {
      "name": "customer",
      "logicalType": "reference",
      "referencedClass":
            "FleetData.Customer",
      "inverseAttribute": "rentals"
    },
    ...
In order to create this relationship, the Customer and RentalContract objects must be updated to reference each other via the designated attributes, rentals and customer.
Let’s get the needed information and then use a transaction to update the objects:
1. Obtain the unique identifier for each of the objects:
Query for the Customer named Jack Green and make a note of its OID.
curl -X POST -H "Content-Type:application/json,Accept:application/json" -d "{\"query\":\"FROM FleetData.Customer WHERE firstName='Jack' AND lastName='Green' RETURN *;\",\"language\": \"do\"}" localhost:8185/v1/query
If needed, repeat the query for the RentalContract with the trackingNumber 122 and make a note of its identifier.
curl -X POST -H "Content-Type:application/json,Accept:application/json" -d "{\"query\":\"FROM FleetData.RentalContract WHERE trackingNumber=122 RETURN *;\",\"language\": \"do\"}" localhost:8185/v1/query
2. Create a file named secondTransaction.txt that includes the following text. If necessary, change the OIDs shown here to the actual OIDs for the Customer and RentalContract objects in your federated database.
[
  {
    "method": "put", "uri": "/v1/object/3-3-1-5", 
    "body": 
      { 
        "attributes":
          { 
            "rentals":
              {
                "elements":
                  [
                    "3-3-1-8"  
                  ]
              }
          }
      }, "result": "keep"
  },
  {
    "method": "put", "uri": "/v1/object/3-3-1-8", 
    "body": 
      { 
        "attributes":
          { 
            "customer": "3-3-1-5"
          }
      }, "result": "keep"
  }
]
3. Post the transaction:
curl -X POST -H "Content-Type:application/json,Accept:application/json" -d @secondTransaction.txt localhost:8185/v1/transaction
The response shows 204 codes.
4. Perform a query to confirm that a Customer with the firstName Jack has a RentalContract with the trackingNumber of 122 among the list of rentals.
curl -X POST -H "Content-Type:application/json,Accept:application/json" -d "{\"query\":\"FROM FleetData.Customer WHERE firstName='Jack' AND ANY(rentals, trackingNumber=122) RETURN *;\",\"language\": \"do\"}" localhost:8185/v1/query