Skip to content

Related Objects

Establishing object relationship

The process of establishing a relationship between multiple objects in Backendless 3.x is by saving the parent object which references its child(ren) in the same object hierarchy/tree. Version 5 changes the mechanism by introducing a dedicated operation which establishes a relationship between the objects. The example below stores two objects in Backendless Data service: Contact and Address and then sets up a relationship between them:

Version 3.x

NSDictionary *joeThePlumber = @{@"name": @"Joe", @"age": @27, @"phone": @"1-972-5551212", @"title": @"Plumber"};
MapDrivenDataStore *contactStorage = [backendless.data ofTable:@"Contact"];
[contactStorage save:joeThePlumber response:^(NSDictionary *savedContact) {

    NSDictionary *address = @{@"street": @"123 Main St.", @"city": @"Denver", @"state": @"Colorado"};
    MapDrivenDataStore *addressStorage = [backendless.data ofTable:@"Address"];
    [addressStorage save:address response:^(NSDictionary *savedAddress) {
        NSMutableDictionary *mutableSavedContact = [savedContact mutableCopy];
        [mutableSavedContact setObject:savedAddress forKey:@"address"];

        [contactStorage save:mutableSavedContact response:^(NSDictionary *updatedContact) {
            NSLog(@"Relation has been set");
        } error:^(Fault *fault) {
            NSLog(@"Error: %@", fault.message);
        }];

    } error:^(Fault *fault) {
        NSLog(@"Error: %@", fault.message);
    }];

} error:^(Fault *fault) {
    NSLog(@"Error: %@", fault.message);
}];
let joeThePlumber = ["name": "Joe", "age": 27, "phone": "1-972-5551212", "title": "Plumber"] as [String: Any]
let contactStorage = Backendless.sharedInstance()?.data.ofTable("Contact")
contactStorage?.save(joeThePlumber, response: { savedContact in

    let address = ["street": "123 Main St.", "city": "Denver", "state": "Colorado"] as [String: Any]
    let addressStorage = Backendless.sharedInstance()?.data.ofTable("Address")
    addressStorage?.save(address, response: { savedAddress in
        if var savedContact = savedContact {
            savedContact["address"] = savedAddress

            contactStorage?.save(savedContact, response: { updatedContact in
                print("Relation has been set")
            }, error: { fault in
                print("Error: \(fault?.message ?? "")")
            })
        }

    }, error: { fault in
        print("Error: \(fault?.message ?? "")")
    })

}, error: { fault in
    print("Error: \(fault?.message ?? "")")
})

Version 5.x

NSDictionary *joeThePlumber = @{@"name": @"Joe", @"age": @27, @"phone": @"1-972-5551212", @"title": @"Plumber"};
MapDrivenDataStore *contactStorage = [Backendless.shared.data ofTable:@"Contact"];
[contactStorage saveWithEntity:joeThePlumber responseHandler:^(NSDictionary *savedContact) {

    NSDictionary *address = @{@"street": @"123 Main St.", @"city": @"Denver", @"state": @"Colorado"};
    MapDrivenDataStore *addressStorage = [Backendless.shared.data ofTable:@"Address"];
    [addressStorage saveWithEntity:address responseHandler:^(NSDictionary *savedAddress) {

        NSString *contactId = [savedContact valueForKey:@"objectId"];
        NSString *addressId = [savedAddress valueForKey:@"objectId"];
        [contactStorage setRelationWithColumnName:@"address" parentObjectId:contactId childrenObjectIds:@[addressId] responseHandler:^(NSNumber *relations) {
            NSLog(@"Relation has been set");
        } errorHandler:^(Fault *fault) {
            NSLog(@"Error: %@", fault.message);
        }];

    } errorHandler:^(Fault *fault) {
        NSLog(@"Error: %@", fault.message);
    }];

} errorHandler:^(Fault *fault) {
    NSLog(@"Error: %@", fault.message);
}];
let joeThePlumber = ["name": "Joe", "age": 27, "phone": "1-972-5551212", "title": "Plumber"] as [String: Any]
let contactStorage = Backendless.shared.data.ofTable("Contact")
contactStorage.save(entity: joeThePlumber, responseHandler: { savedContact in

    let address = ["street": "123 Main St.", "city": "Denver", "state": "Colorado"] as [String: Any]
    let addressStorage = Backendless.shared.data.ofTable("Address")
    addressStorage.save(entity: address, responseHandler: { savedAddress in

        if let contactId = savedContact["objectId"] as? String,
            let addressId = savedAddress["objectId"] as? String {
            contactStorage.setRelation(columnName: "address", parentObjectId: contactId, childrenObjectIds: [addressId], responseHandler: { relations in
                print("Relation has been set")
            }, errorHandler: { fault in
                print("Error: \(fault.message ?? "")")
            })
        }

    }, errorHandler: { fault in
        print("Error: \(fault.message ?? "")")
    })

}, errorHandler: { fault in
    print("Error: \(fault.message ?? "")")
})

Deleting/breaking object relationship

Similar to establishing a relationship between objects, Backendless 3.x relied on the update operation which sends the parent object to the server with an updated list of child objects. Any children removed from the collection on the client-side, are removed on the server as a result of the update call. Version 5 introduces a dedicated method to remove a relationship between objects. The example below removes a relationship between a Contact object and the first related Address object:

Version 3.x

// load parent object
MapDrivenDataStore *contactStorage = [backendless.data ofTable:@"Contact"];
[contactStorage findById:@"XXXXX" relationsDepth:1 response:^(NSDictionary *contact) {             
    // load parent object relations
    NSArray *relationNames = @[@"address"];
    [contactStorage loadRelations:contact relations:relationNames response:^(NSDictionary *relations) {              
        // delete the relation between the parent object and children for the "address" column
        NSMutableDictionary *mutableContact = [contact mutableCopy];
        [mutableContact setObject:[NSNull null] forKey:@"address"];
        [contactStorage save:mutableContact response:^(NSDictionary *updatedContact) {
            NSLog(@"Relation has been removed");
        } error:^(Fault *fault) {
            NSLog(@"Error: %@", fault.message);
        }];                     
    } error:^(Fault *fault) {
        NSLog(@"Error: %@", fault.message);
    }];              
} error:^(Fault *fault) {
        NSLog(@"Error: %@", fault.message);
}];
// load parent object
let contactStorage = Backendless.sharedInstance()?.data.ofTable("Contact")
contactStorage?.find(byId: "XXXXX", relationsDepth: 1, response: { contact in            
    // load parent object relations
    let relationNames = ["address"]
    contactStorage?.loadRelations(contact, relations: relationNames, response: { relations in
        // delete the relation between the parent object and children for the "address" column
        if var contact = contact {
            contact["address"] = NSNull()
            contactStorage?.save(contact, response: { updatedContact in
                print("Relation has been removed")
            }, error: { fault in
                print("Error: \(fault?.message ?? "")")
            })
        }
    }, error: { fault in
        print("Error: \(fault?.message ?? "")")
    })
}, error: { fault in
    print("Error: \(fault?.message ?? "")")
})

Version 5.x

// load parent object
MapDrivenDataStore *contactStorage = [Backendless.shared.data ofTable:@"Contact"];
DataQueryBuilder *queryBuilder = [DataQueryBuilder new];
[queryBuilder setRelationsDepthWithRelationsDepth:1];
NSArray *relationNames = @[@"address"];
[queryBuilder setRelatedWithRelated:relationNames];
[contactStorage findByIdWithObjectId:@"XXXXX" queryBuilder:queryBuilder responseHandler:^(NSDictionary *contact) {
    // delete the relation between the parent object and children for the "address" column
    NSString *parentId = [contact valueForKey:@"objectId"];
    NSString *addressId = [[contact valueForKey:@"address"] valueForKey:@"objectId"];
    [contactStorage deleteRelationWithColumnName:@"address" parentObjectId:parentId childrenObjectIds:@[addressId] responseHandler:^(NSNumber *removedRelations) {
        NSLog(@"Relation has been removed");
    } errorHandler:^(Fault *fault) {
        NSLog(@"Error: %@", fault.message);
    }];        
} errorHandler:^(Fault *fault) {
    NSLog(@"Error: %@", fault.message);
}];
// load parent object
let contactStorage = Backendless.shared.data.ofTable("Contact")
let queryBuilder = DataQueryBuilder()
queryBuilder.setRelationsDepth(relationsDepth: 1)
let relationNames = ["address"]
queryBuilder.setRelated(related: relationNames)
contactStorage.findById(objectId: "XXXXX", queryBuilder: queryBuilder, responseHandler: { contact in
    // delete the relation between the parent object and children for the "address" column
    if let parentId = contact["objectId"] as? String,
        let address = contact["address"] as? [String: Any],
        let addressId = address["objectId"] as? String {
        contactStorage.deleteRelation(columnName: "address", parentObjectId: parentId, childrenObjectIds: [addressId], responseHandler: { removedRelations in
            print("Relation has been removed")
        }, errorHandler: { fault in
            print("Error: \(fault.message ?? "")")
        })
    }
}, errorHandler: { fault in
    print("Error: \(fault.message ?? "")")
})

Additional resources: