Backendless Support
 

Loading related data objects - the 'one-step/dynamic' approach

Using Backendless approach for loading  complex data objects from the persistent storage using the "auto-load" technique a developer can statically identify specific (child) properties which should be returned along with the parent object(s) when a client app sends a request to load them. That approach works well for object relations which must be unconditionally returned with the parent object.

However, there are many scenarios when the client app must control which relations should be preloaded and returned along with the parent.  The API described below allows to accomplish that.

Consider the following example which uses the client-side code generated by Backendless based on the database schema. In that schema the Restaurant table has the "locations" column which represents a one-to-many relationship between the Restaurant and Locations table. This means that a restaurant may have several related locations as shown in the screenshots below:

The restaurant objects: 

The related location object for the "Cantina Laredo" restaurant: 

JAVA

Synchronous API (Plain Java only):

private static void loadRelationsSync()
{
 System.out.println( "\n============ Loading relations with the SYNC API ============" );
 QueryOptions queryOptions = new QueryOptions();
 queryOptions.addRelated( "locations" );
 BackendlessDataQuery dataQuery = new BackendlessDataQuery();
 dataQuery.setQueryOptions( queryOptions );
 BackendlessCollection<Restaurant> restaurants = Backendless.Data.of( Restaurant.class ).find( dataQuery );
 System.out.println( "Loaded " + restaurants.getCurrentPage().size() + " restaurant objects" );
 System.out.println( "Total restaurants in the Backendless storage - " + restaurants.getTotalObjects() );
 Iterator<Restaurant> iterator = restaurants.getCurrentPage().iterator();
 while (iterator.hasNext())
 {
 Restaurant restaurant = iterator.next();
 System.out.println( "\nRestaurant name = " + restaurant.getName() );
 printLocations( restaurant.getLocations() );
 }
}
Asynchronous API (Android and Plain Java):
private static void loadRelationsAsync()throws Throwable
{
System.out.println("\n============ Loading relations with the ASYNC API ============");
finalCountDownLatch latch=newCountDownLatch(1);
AsyncCallback<BackendlessCollection<Restaurant>>callback=newAsyncCallback<BackendlessCollection<Restaurant>>()
{
@Override
publicvoidhandleResponse(BackendlessCollection<Restaurant>restaurants)
{
System.out.println("Loaded "+restaurants.getCurrentPage().size()+" restaurant objects");
System.out.println("Total restaurants in the Backendless storage - "+restaurants.getTotalObjects());
Iterator<Restaurant>iterator=restaurants.getCurrentPage().iterator();
while(iterator.hasNext())
{
Restaurant restaurant=iterator.next();
System.out.println("\nRestaurant name = "+restaurant.getName());
printLocations(restaurant.getLocations());
}
latch.countDown();
}
@Override
publicvoidhandleFault(BackendlessFault backendlessFault)
{
}
};
QueryOptions queryOptions=newQueryOptions();
queryOptions.addRelated("locations");
BackendlessDataQuery dataQuery=newBackendlessDataQuery();
dataQuery.setQueryOptions(queryOptions);
Backendless.Data.of(Restaurant.class).find(dataQuery,callback);
latch.await();
}

Notice the addRelated method in the QueryOptions class in the Java, Objective-C and Swift examples. The method requests that the data objects referenced by "locations" column must be initialized and returned with the every parent Restaurant object. The JavaScript example uses the relations array in the QueryOptions object for the same purpose. The printLocations method displays the loaded Locations objects:

Java
private static void printLocations( List<Location> locations )
{
 if( locations == null )
 {
 System.out.println( "Restaurant locations have not been loaded" );
 }
 else if( locations.size() == 0 )
 {
 System.out.println( "There are no related locations" );
 }
 else
 {
 Iterator<Location> iterator = locations.iterator();
 while( iterator.hasNext() )
 {
 Location location = iterator.next();
 System.out.println( "Location: Street address - " + location.getStreetAddress() + ", City - " + location.getCity() );
 }
 }
}

The code above produces the following output.

Notice that the "Cantina Laredo" restaurant is fetched with the related location:

============ Loading relations with the SYNC API ============
Loaded 4 restaurant objects
Total restaurants in the Backendless storage - 4
Restaurant name = McDonald's
There are no related locations
Restaurant name = Buca Di Bepo
There are no related locations
Restaurant name = Cantina Laredo
Location: Street address - 123 Main St., City - Frisco
Restaurant name = Endless Sweets
There are no related locations
============ Loading relations with the ASYNC API ============
Loaded 4 restaurant objects
Total restaurants in the Backendless storage - 4
Restaurant name = McDonald's
There are no related locations
Restaurant name = Buca Di Bepo
There are no related locations
Restaurant name = Cantina Laredo
Location: Street address - 123 Main St., City - Frisco
Restaurant name = Endless Sweets
There are no related locations

See the documentation for more information on loading related objects with the "one-step" approach.

Is article helpful?