Another post covered how to retrieve data objects from Backendless. The code in that article loads a collection of the Restaurant objects and although it does not show it, the related collection of the Location objects arrives un-initialized. That is the default behavior of Backendless Database when it comes to loading related objects. The code below demonstrates that the collection is indeed empty (null). (The code in these examples is from the article describing how to generate client-side code based on data tables.)
private static void printLocations(List<Location> locations) { if (locations == null) { Log.i(TAG, "Restaurant locations have not been loaded"); } else if (locations.size() == 0) { Log.i(TAG, "There are no related locations"); } else { for (Location location : locations) { Log.i(TAG, "Location: Street address - " + location.getStreetAddress() + ", City - " + location.getCity()); } } }
API example:
private static void fetchingFirstPageAsync() { final long startTime = System.currentTimeMillis(); final AsyncCallback<List<Restaurant>> callback = new AsyncCallback<List<Restaurant>>() { @Override public void handleResponse(List<Restaurant> restaurants) { Log.i(TAG, "Loaded " + restaurants.size() + " restaurant objects"); for (Restaurant restaurant : restaurants) { Log.i(TAG, "Restaurant name = " + restaurant.getName()); printLocations(restaurant.getLocations()); } Log.i(TAG, "Total time (ms) - " + (System.currentTimeMillis() - startTime)); } @Override public void handleFault(BackendlessFault fault) { Log.e(TAG, fault.getMessage()); } }; Backendless.Data.of(Restaurant.class).getObjectCount(new AsyncCallback<Integer>() { @Override public void handleResponse(Integer count) { Log.i(TAG, "Total restaurants in the Backendless storage - " + count); Backendless.Data.of(Restaurant.class).find(callback); } @Override public void handleFault(BackendlessFault fault) { Log.e(TAG, fault.getMessage()); } }); }
private fun printLocations(locations: List<Location>?) { when { locations == null -> Log.i(TAG, "Restaurant locations have not been loaded") locations.size == 0 -> Log.i(TAG, "There are no related locations") else -> for (location in locations) { Log.i(TAG, "Location: Street address - ${location.streetAddress}, City - ${location.city}") } } }
API example:
private fun fetchingFirstPageAsync() { val startTime = System.currentTimeMillis() val callback = object : AsyncCallback<List<Restaurant>> { override fun handleResponse(restaurants: List<Restaurant>) { Log.i(TAG, "Loaded ${restaurants.size} restaurant objects") for (restaurant in restaurants) { Log.i(TAG, "Restaurant name = ${restaurant.name}") printLocations(restaurant.locations) } Log.i(TAG, "Total time (ms) - ${System.currentTimeMillis() - startTime}") } override fun handleFault(fault: BackendlessFault) { Log.e(TAG, fault.message) } } Backendless.Data.of(Restaurant::class.java).getObjectCount(object : AsyncCallback { override fun handleResponse(count: Int?) { Log.i(TAG, "Total restaurants in the Backendless storage - $count") Backendless.Data.of(Restaurant::class.java).find(callback) } override fun handleFault(fault: BackendlessFault) { Log.e(TAG, fault.message) } }) }
@interface Restaurant : NSObject @property (strong, nonatomic) NSString *name; @property (strong, nonatomic) NSArray *locations; @end @interface Location : NSObject @property (strong, nonatomic) NSString *city; @property (strong, nonatomic) NSString *street; @end
Method to print out related locations:
- (void)printLocations:(NSArray<Location *> *)locations { if (!locations) { NSLog(@"Restaurant locations have not been loaded"); } else { if (locations.count == 0) { NSLog(@"There are no related locations"); } else { for (Location *location in locations) { NSLog(@"Location: Street address - %@, City - %@", location.street, location.city); } } } }
API example:
NSLog(@"============ Fetching first page ============"); NSDate *startTime = [NSDate date]; DataStoreFactory *dataStore = [Backendless.shared.data of:[Restaurant class]]; [dataStore findWithResponseHandler:^(NSArray *restaurants) { NSLog(@"Loaded %lu restaurant objects", (unsigned long)restaurants.count); [dataStore getObjectCountWithResponseHandler:^(NSInteger totalRestaurants) { NSLog(@"Total restaurants in the Backendless storage - %li",(long)totalRestaurants); for (Restaurant *restaurant in restaurants) { NSLog(@"\nRestaurant name = %@", restaurant.name); [self printLocations:restaurant.locations]; } NSLog(@"Total time (ms) - %g", 1000*[[NSDate date] timeIntervalSinceDate:startTime]); } errorHandler:^(Fault *fault) { NSLog(@"Error: %@", fault.message); }]; } errorHandler:^(Fault *fault) { NSLog(@"Error: %@", fault.message); }];
@objcMembers class Restaurant: NSObject { var name: String? var locations: [Location]? } @objcMembers class Location: NSObject { var city: String? var street: String? }
Method to print out related locations:
func printLocations(_ locations: [Location]?) { if locations == nil { print("Restaurant locations have not been loaded") } else if let locations = locations { if locations.count == 0 { print("There are no related locations") } else { for location in locations { if let city = location.city, let street = location.street { print("Location: Street address - \(street), City - \(city)") } } } } }
API example:
print("============ Fetching first page ============") let startTime = Date() let dataStore = Backendless.shared.data.of(Restaurant.self) dataStore.find(responseHandler: { restaurants in print("Loaded \(restaurants.count) restaurant objects") dataStore.getObjectCount(responseHandler: { totalRestaurants in print("Total restaurants in the Backendless storage - \(totalRestaurants)") if let restaurants = restaurants as? [Restaurant] { for restaurant in restaurants { print("\nRestaurant name = \(restaurant.name ?? "")") self.printLocations(restaurant.locations) } print("Total time (ms) - \(Int(Date().timeIntervalSince(startTime) * 1000))") } }, errorHandler: { fault in print("Error: \(fault.message ?? "")") }) }, errorHandler: { fault in print("Error: \(fault.message ?? "")") })
const Backendless = require('backendless') /* Or use `import Backendless from 'backendless'` for client side. If you don't use npm or yarn to install modules, you can add the following line <script src="//api.backendless.com/sdk/js/latest/backendless.min.js"></script> to your index.html file and use the global Backendless variable. */ Backendless.initApp('YOUR_APP_ID', 'YOUR_JS_API_KEY') const loadRestaurants = () => { return Backendless.Data.of('Restaurant').find() } const onSuccess = restaurants => { restaurants.forEach(restaurant => { printLocations(restaurant.locations) }) } const printLocations = locations => { if (!locations) { return console.log('Restaurant locations have not been loaded') } if (!locations.length) { return console.log('There are no related locations') } locations.forEach(location => { console.log(`Location: Street address - ${ location.streetAddress }, City - ${ location.city }`) }) } const onError = error => { console.error('Server reported an error: ', error.message) console.error('error code: ', error.code) console.error('http status: ', error.status) } Promise.resolve() .then(loadRestaurants) .then(onSuccess) .catch(onError)
static void _printLocations(List<Map> locations) { if (locations == null) { print("Restaurant locations have not been loaded"); } else if (locations.isEmpty) { print("There are no related locations"); } else { for (Map location in locations) { print("Location: Street address - ${location['streetAddress']}, City - ${location['city']}"); } } }
API example:
static void _fetchingFirstPageAsync() { int startTime = DateTime.now().millisecondsSinceEpoch; Backendless.Data.of("Restaurant").getObjectCount().then((count) { print("Total restaurants in the Backendless storage - $count"); Backendless.Data.of("Restaurant").find().then((restaurants) { print("Loaded ${restaurants.length} restaurant objects"); restaurants.forEach((restaurant) { print("Restaurant name = ${restaurant['name']}"); _printLocations(restaurant['locations'].cast
============ Fetching first page using the SYNC API ============ Loaded 4 restaurant objects Total restaurants in the Backendless storage - 4 Restaurant name = McDonald's Restaurant locations have not been loaded Restaurant name = Buca Di Bepo Restaurant locations have not been loaded Restaurant name = Cantina Laredo Restaurant locations have not been loaded Restaurant name = Endless Sweets Restaurant locations have not been loaded Total time (ms) - 437 ============ Fetching first page using the ASYNC API ============ Loaded 4 restaurant objects Total restaurants in the Backendless storage - 4 Restaurant name = McDonald's Restaurant locations have not been loaded Restaurant name = Buca Di Bepo Restaurant locations have not been loaded Restaurant name = Cantina Laredo Restaurant locations have not been loaded Restaurant name = Endless Sweets Restaurant locations have not been loaded Total time (ms) - 202
There are several approaches for loading related objects for a parent entity. This post reviews one of them – the ‘auto-load’ option. This option is available in Backendless Console. The screenshot below shows the Restaurant table. Notice the ‘auto load’ checkbox in the “owner” and “locations” columns:
When the checkbox is selected, Backendless automatically includes the related objects for the column into the response. If you select the auto-load checkbox for the “locations” column and re-run the code above, you will get the following output (JAVA example):
============ Fetching first page using 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 Total time (ms) - 548 ============ Fetching first page using 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 Total time (ms) - 305
As you can see from the output, the related location for the “Cantina Laredo” restaurant has been loaded without making any changes to the code. All it took is the selected checkbox in the Console.
Enjoy!