Implementing Hierarchical Relationship with Corda QueryableState

January 02, 2020

Implementing hierarchical relationships with Corda QueryableState

This is a continuation of my previous blog on QueryableState, where I discussed how to implement a QueryableState to persist state data into a custom database table. If you have not read the previous blog, I would recommend taking a couple of minutes to go through it first, as I would be reusing most of what we developed in the previous blog.

The previous blog used an Insurance state with few fields to persist into the custom database table. However, things may not always be as simple, one may come across complex objects like our Insurance state. The insurance may be for an asset, let’s say a vehicle, in which case the vehicle information would also be associated with the Insurance state. It would be a good idea to save the vehicle information and the insurance information in separate tables. Here in this scenario, we need to have two tables with a one-to-one relationship.

Another scenario could be a one-to-many relationship/ many-to-one relationship, for example, our insurance may have multiple claims associated with it, we would want to save the claims information in a separate table having a many-to-one relation with the insurance table.

Hierarchical Relationships

One-to-One Relationship

Let’s update our previous code to implement a one-to-one relationship.

Step1: Create the Vehicle class

The class needs to be annotated with CordaSerializable , since Corda uses its own serialization framework and the annotation is necessary for serializing the object to pass across Corda nodes. This is a simple Java class containing the details of the vehicle.Step2: Create the Vehicle entity

Step3: Update the Insurance entity

  1. The PersistentInsurance entity needs to be updated to add the One-to-One relationship with the PersistentVehicle.
  2. Update the constructors accordingly to accommodate the new vehicle field introduced.
  3. Add Getter for the vehicle field.
@OneToOne(cascade = CascadeType.PERSIST)
@JoinColumns({
        @JoinColumn(name = "id", referencedColumnName = "id"),
        @JoinColumn(name = "registrationNumber", referencedColumnName = "registrationNumber"),
})
private final PersistentVehicle vehicle;

Step4: Update MappedSchema to include the PersistentVehicle

The InsuranceSchemaV1 needs to be updated to support the new PersistentVehicle entity created for the vehicle.

public InsuranceSchemaV1() {
    super(InsuranceSchemaFamily.class, 1, ImmutableList.of
              (PersistentInsurance.class,PersistentVehicle.class));
}

Step5: Update Insurance state

  1. Update the insurance state to add the vehicle field.
  2. Update the constructor to add the vehicle field as a parameter.
  3. Add a getter for the vehicle.
  4. Update generateMappedObject() method to add logic for generating the PersistentVehicle.

With the above code, we should be able to have a one-to-one relationship in our database between vehicle_deatil and insurance_detail tables.

Shown below is are snapshots of the database tables after a state is issued with the updated code.

INSURANCE_DETAILS
VEHICLE_DETAIL

One-to-Many Relationship

Let’s add the claims to our Insurance state, to showcase a One-to-Many relationship. The steps to follow are very much similar to what we did for One-to-One relationship.

Step1: Create the Claim class

Similar to the Vehicle class, the Claim class is also a simple Java class containing the claim details.

Step2: Create the Claim entity

Step3: Update Insurance entity

  1. A list of PersistentClaim needs to be added to PersistentInsurance to represent the One-to-Many relationship.
  2. Update the constructors accordingly to accommodate the new claims field introduced.
  3. Add Getter for the claims field.
@OneToMany(cascade = CascadeType.PERSIST)
@JoinColumns({
        @JoinColumn(name = "output_index", referencedColumnName = "output_index"),
        @JoinColumn(name = "transaction_id", referencedColumnName = "transaction_id"),
})
private List<PersistentClaim> claims;

Step4: Update MappedSchema to include the PersistentClaim

The InsuranceSchemaV1 needs to be updated to support the new PersistentClaim entity created for the claims.

public InsuranceSchemaV1() {
    super(InsuranceSchemaFamily.class, 1, ImmutableList.of(
            PersistentInsurance.class,
            PersistentVehicle.class, 
            PersistentClaim.class)
    );
}

Step5: Update Insurance state

  1. Update the insurance state to add the claims field.
  2. Update the constructor to add the claims field as a parameter.
  3. Add a getter for the claims field.
  4. Update generateMappedObject() method to add logic for generating the list of PersistentClaim.

With the above code, we should be able to have a one-to-one relationship in our database between insurance_detail and claim_detail tables.

Shown below is are snapshots of the database tables after a state is issued with the updated code.

INSURANCE_DETAIL
VEHICLE_DETAIL
CLAIM_DETAIL

Sample Code

The sample code used in this blog can be found here:

corda/samples

Further reading

More information on QueryableState can be found on the Corda Docs site. Extra detail not included in this post can be found there.

If you have come this far it means you are genuinely interested in Corda. You may consider joining us in our public slack channel if you have questions or are interested in learning more about Corda. Other ways to connect.

— Ashutosh Meher, Developer Relations at R3


Implementing Hierarchical Relationship with Corda QueryableState was originally published in Corda on Medium, where people are continuing the conversation by highlighting and responding to this story.