Saving Data Objects

Top  Previous  Next

The API to save an object can be used for two separate scenarios: if an object has been previously saved, it is updated in the data store, otherwise it is saved (created). The save operation checks if the object has objectId assigned by the server. in that case, the object is updated, otherwise it is created in the Backendless data store. In case when there is no table for the persisted object, Backendless creates one and maps table's columns to the object's properties.

The objectId property is automatically assigned to all persisted objects when they are initially saved. See the Data Object section for details on objectId.

 

The Data Service API  is available via the Backendless singleton object:

// The singleton reference is defined in Backendless.h:
#define backendless [Backendless sharedInstance]
// Use the following code to obtain the backendless singleton object:
var backendless = Backendless.sharedInstance()

Your application objects are stored in Backendless tables. Objects can be of custom classes defined in your application or represented as instances of NSDictionary (Objective-C) or plain object maps (Swift). With the custom classes approach, instances of class A are stored in table "A" - Backendless creates tables automatically, however, if you prefer, you can create your tables and define the schema using Backendless console. Each data table can be accessed using a 'data store' object - by using the IDataStore protocol. A reference to a data store can be obtained using the following code:

// obtaining IDataStore for the custom-class approach:
id<IDataStore> dataStore = [backendless.data of:[YOUR-CLASS class]];

// obtaining IDataStore for the dictionary-based approach:
id<IDataStore> dataStore = [backendless.data ofTable:@"TABLE-NAME"];
// obtaining IDataStore for the custom-class approach:
let dataStore = backendless.data of(YOUR-CLASS.ofClass());

// obtaining IDataStore for the map-based approach:
let dataStore = backendless.data ofTable("TABLE-NAME");

where

YOUR-CLASS is the class which instances will be stored in a corresponding table.

"TABLE-NAME" is the name of the table for which to get the data store. All subsequent data store operations will be performed in the specified table.

A data store object provides the following APIs for saving data objects in Backendless:

Synchronous Methods:

// **********************************************************************
// CUSTOM CLASS APPROACH
// **********************************************************************
// stores new object in Backendless and returns created object. If request 
// results in an error, it is thrown as an exception
-(id)save:(id)entity;

// stores new object in Backendless and returns created object. If request 
// results in an error, it is delivered through the "fault" object
-(id)save:(id)entity error:(Fault **)fault;

// **********************************************************************
// DICTIONARY APPROACH
// **********************************************************************
// stores new object in Backendless and returns created object. If request 
// results in an error, it is thrown as an exception
 -(NSDictionary<NSString*,id> *)save:(NSDictionary<NSString*,id> *)entity;
 
 // stores new object in Backendless and returns created object. If request 
// results in an error, it is delivered through the "fault" object
 -(NSDictionary<NSString*,id> *)save:(NSDictionary<NSString*,id> *)entity 
                                         fault:(Fault **)fault;
// **********************************************************************
// CUSTOM CLASS APPROACH
// **********************************************************************
// stores new object in Backendless and returns created object. If request 
// results in an error, it is thrown as an exception
func save(_ entity: AnyObject!) -> AnyObject!

// stores new object in Backendless and returns created object. If request 
// results in an error, it is delivered through the "fault" object
func save(_ entity: AnyObject!, error fault: AutoreleasingUnsafeMutablePointer<Fault?>) -> AnyObject!

// **********************************************************************
// MAP-BASED APPROACH
// **********************************************************************
// stores new object in Backendless and returns created object. If request 
// results in an error, it is thrown as an exception
func save(_ entity: [String:AnyObject]!) -> [String:AnyObject]!

// stores new object in Backendless and returns created object. If request 
// results in an error, it is delivered through the "fault" object
func save(_ entity: [String:AnyObject]!, 
          error fault: AutoreleasingUnsafeMutablePointer<Fault?>) -> [String:AnyObject]!

Asynchronous Methods:

// **********************************************************************
// CUSTOM CLASS APPROACH
// **********************************************************************
// stores new object in Backendless. Server's response (result or error) is 
// delivered through the responder object
-(void)save:(id)entity  
             responder:(id <IResponder>)responder;
             
// stores new object in Backendless. Server's response (result or error) is 
// delivered through the block-based callbacks
-(void)save:(id)entity  
            response:(void(^)(NSDictionary *))responseBlock 
            error:(void(^)(Fault *))errorBlock;
            
// **********************************************************************
// DICTIONARY APPROACH
// **********************************************************************
// stores new object in Backendless. Server's response (result or error) is 
// delivered through the responder object
 -(void)save:(NSDictionary<NSString*,id> *)entity 
              responder:(id <IResponder>)responder;
 
// stores new object in Backendless. Server's response (result or error) is 
// delivered through the block-based callbacks
 -(void)save:(NSDictionary<NSString*,id> *)entity 
              response:(void(^)(NSDictionary<NSString*,id> *))responseBlock 
              error:(void(^)(Fault *))errorBlock;
// **********************************************************************
// CUSTOM CLASS APPROACH
// **********************************************************************
// stores new object in Backendless. Server's response (result or error) is 
// delivered through the responder object
func save(_ entity: AnyObject!, 
          responder responder: IResponder!) -> Void

// stores new object in Backendless. Server's response (result or error) is 
// delivered through the block-based callbacks
func save(_ entity: AnyObject!, 
          response responseBlock: ((AnyObject!) -> Void)!, 
          error errorBlock: ((Fault!) -> Void)!) -> Void

// **********************************************************************
// MAP-BASED APPROACH
// **********************************************************************      
// stores new object in Backendless. Server's response (result or error) is 
// delivered through the responder object    
func save(_ entity: [String:AnyObject]!, responder responder: IResponder!) -> Void

// stores new object in Backendless. Server's response (result or error) is 
// delivered through the block-based callbacks
func save(_ entity: [String:AnyObject]!, 
          response responseBlock: (([String:AnyObject]!) -> Void)!, 
          error errorBlock: ((Fault!) -> Void)!) -> Void

where:

entity- Object to persist
responder- a responder object which will receive a callback when the method successfully saves the object or if an error occurs.
responseBlock- a block to handle successful result of an asynchronous call.
errorBlock- a block to handle fault result of an asynchronous call.

Return Value:

The synchronous method returns the saved object. The asynchronous call receives the return value through a callback executed on the either the responder object or through the block-callback.

Example:

Consider the following class which will be used in the example. The class will be used to create data objects persisted in Backendless:

@interface Contact: NSObject
@property (nonatomic, strong) NSString *objectId;
@property (nonatomic, strong) NSDate *created;
@property (nonatomic, strong) NSDate *updated;
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) NSString *phone;
@property (nonatomic) NSUInteger age;
@end

@implementation Contact
@end
class Contact : NSObject {
    
    var objectId : String?
    var name : String?
    var age: Int = 0
    var phone : String?
    var title : String?
}

The following code saves an instance of the Contact class in Backendless:

-(void)saveNewContact
{
    Responder *responder = [Responder responder:self 
                            selResponseHandler:@selector(responseHandler:) 
                            selErrorHandler:@selector(errorHandler:)];
    Contact *contact = [Contact new];
    contact.age = 21;
    contact.title = @"title";
    contact.name = @"name";
    contact.phone = @"555-555-555";
    id<IDataStore> dataStore = [backendless.persistenceService of:[Contact class]];
    [dataStore save:contact responder:responder];
}

#pragma mark - responder
-(id)responseHandler:(id)response
{
    NSLog(@"%@", response);
    return response;
}
-(id)errorHandler:(Fault *)fault
{
    NSLog(@"%@", fault.detail);
    return fault;
}
  func saveNewContact() {
        
        let contact = Contact()
        contact.name = "Jack Daniels"
        contact.age = 147
        contact.phone = "777-777-777"
        contact.title = "Favorites"
        
        let dataStore = backendless.data.of(Contact.ofClass())
        
        // save object synchronously
        var error: Fault?
        let result = dataStore.save(contact, fault: &error) as? Contact
        if error == nil {
            print("Contact has been saved: \(result!.objectId)")
        }
        else {
            print("Server reported an error: \(error)")
        }
        
        // save object asynchronously
        dataStore.save(
            contact,
            response: { (result: AnyObject!) -> Void in
                let obj = result as! Contact
                print("Contact has been saved: \(obj.objectId)")
            },
            error: { (fault: Fault!) -> Void in
                print("fServer reported an error: \(fault)")
        })
    }
With the dictionary/map-driven approach, objects sent to the backend are represented as plain NSDictionary (Obj-C) or untyped object maps (Swift):

-(void)saveNewContact {
    
    NSDictionary *contact = @{
                              @"name": @"Jack Daniels",
                              @"age": @(147),
                              @"phone": @"777-777-777",
                              @"title": @"Favorites"
                              };
    
    // sync
    Fault *error = nil;
    contact = [[backendless.data ofTable:@"Contact"] save:contact fault:&error];
    if (!error) {
        NSLog(@"Data has been saved (SYNC): %@", contact[@"objectId"]);
    }
    else {
        NSLog(@"Server reported an error: %@", error);
    }
    
    // async
    [[backendless.data ofTable:@"Contact"] save:contact
          response:^(NSDictionary<NSString*,id> *contact) {
              NSLog(@"Data has been saved (ASYNC): %@", contact[@"objectId"]);
          }
          error:^(Fault *fault) {
              NSLog(@"importGroups: %@", fault);
          }];
}
    func saveNewContactMap() {
        
        let contact = [
            "name": "Jack Daniels",
            "age": 147,
            "phone": "777-777-777",
            "title": "Favorites"
        ]
        
        let dataStore = Backendless.sharedInstance().data.ofTable("Contact")
        
        // save object synchronously
        var error: Fault?
        let result = dataStore.save(contact, fault: &error)
        if error == nil {
            print("Contact has been saved (SYNC): \(result!["objectId"])")
        }
        else {
            print("Server reported an error (SYNC): \(error)")
        }
        
        // save object asynchronously
        dataStore.save(
            contact,
            response: { (result: [String:AnyObject]!) -> Void in
                print("Contact has been saved (ASYNC): \(result!["objectId"])")
            },
            error: { (fault: Fault!) -> Void in
                print("Server reported an error (ASYNC): \(fault)")
        })
    }

 

 


Please let us know how we can improve the documentation by leaving a comment. All technical questions should be posted to the Backendless Support forum. We do not respond to the technical questions on the documentation pages.: