Syncing Up by External ID

Mobile SDK enhances its sync-up functionality by adding the ability to sync up by external ID. To use this feature, you specify an external ID field name in the sync up target definition. If a soup record is marked as locally created, updated, or deleted and has an external ID value, Mobile Sync syncs it up using upsert instead of create. If the record also has a valid Id value, however, Mobile Sync updates the indicated Salesforce record.

You can configure the external ID field name in Mobile Sync configuration files or in code. External IDs are supported for standard sync up targets and parent-child sync up targets.

Advantage of Using Upserts

Upserts are useful for avoiding record duplication. When your sync target supports an external ID field name and a locally created record has a value for that field, Mobile Sync upserts, rather than creates, the server record.

True upsert behavior allows the app to deal with network disconnection gracefully. If the network disconnects during a sync up, the app typically doesn’t know whether its last request reached the server. In this case, the app’s logical reaction when connectivity returns is to resync.

However, consider what happens if the server did in fact received your request and created the record. In this case, resyncing without using upsert creates a duplicate record. If you’ve configured external ID field names in the sync up target, the resync can run safely: upsert finds the recently created record and merely rewrites the record’s fields with their existing values.

Parent-Child Sync Up Recommendation

In parent-child scenarios, you can specify the external ID field name for parent or children, or both. For a graceful offline experience, it’s best to define the external ID field name in parent and children sync configurations.

Configuring an External ID Field Name Declaratively

Here are examples of specifying an external ID field name declaratively for a target in sync configuration files.
Standard Sync Up Target
1{ 
2  “syncName”: “myExampleSyncUp”, 
3  “syncType”: “syncUp”, 
4  “soupName”: “MySoup”, 
5    “target”: { 
6               “idFieldName”: “Id”, 
7               “modificationDateFieldName”: “LastModifiedDate”, 
8               “externalIdFieldName”: “TheExternalId” 
9   }, 
10   “options”: { 
11               “fieldlist”: [“Name”, “Description”], 
12               “mergeMode”: “OVERWRITE” 
13   }
14}
Parent-Child Sync Up Target
1{
2   "syncName":"parentChildrenSyncUp",
3   "syncType":"syncUp",
4   "soupName":"accounts",
5   "target":{
6      "iOSImpl":"SFParentChildrenSyncUpTarget",
7      "androidImpl":"com.salesforce.androidsdk.mobilesync.target.ParentChildrenSyncUpTarget",
8      "parent":{
9         "idFieldName":"IdX",
10         "externalIdFieldName":"ExternalIdX",
11         "sobjectType":"Account",
12         "modificationDateFieldName":"LastModifiedDateX",
13         "soupName":"accounts"
14      },
15      "createFieldlist":[
16         "IdX",
17         "Name",
18         "Description"
19      ],
20      "updateFieldlist":[
21         "Name",
22         "Description"
23      ],
24      "children":{
25         "parentIdFieldName":"AccountId",
26         "idFieldName":"IdY",
27         "externalIdFieldName":"ExternalIdY",
28         "sobjectType":"Contact",
29         "modificationDateFieldName":"LastModifiedDateY",
30         "soupName":"contacts",
31         "sobjectTypePlural":"Contacts"
32      },
33      "childrenCreateFieldlist":[
34         "LastName",
35         "AccountId"
36      ],
37      "childrenUpdateFieldlist":[
38         "FirstName",
39         "AccountId"
40      ],
41      "relationshipType":"MASTER_DETAIL"
42   },
43   "options":{
44      "fieldlist":[
45         
46      ],
47      "mergeMode":"LEAVE_IF_CHANGED"
48   }
49}
Extended Example
For a “one-stop” example of many types of sync configurations, see shared/example.usersyncs.json in the github.com/forcedotcom/SalesforceMobileSDK-Shared GitHub repo.

Configuring External ID Field Name Programmatically

iOS
For standard sync up targets:
Swift
Set the externalIdFieldName property in your SyncUpTarget or BatchSyncUpTarget class.
Objective-C
Set the externalIdFieldName property in your SFSyncUpTarget or SFBatchSyncUpTarget class.
For parent-child sync up targets:
Swift
Objective-C
Pass a non-nil value to the externalIdFieldName parameters of these factory methods (new in Mobile SDK 9.0):
1// From SFParentInfo.h
2+ (SFParentInfo *)newWithSObjectType:(NSString *)sobjectType
3                            soupName:(NSString *)soupName
4                         idFieldName:(NSString *)idFieldName
5           modificationDateFieldName:(NSString *)modificationDateFieldName
6                 externalIdFieldName:(NSString * __nullable) externalIdFieldName;
7
8// From SFChildrenInfo.h
9+ (SFChildrenInfo *)newWithSObjectType:(NSString *)sobjectType
10                     sobjectTypePlural:(NSString *)sobjectTypePlural
11                              soupName:(NSString *)soupName
12                     parentIdFieldName:(NSString *)parentIdFieldName
13                           idFieldName:(NSString *)idFieldName
14             modificationDateFieldName:(NSString *)modificationDateFieldName
15                   externalIdFieldName:(NSString * __nullable)externalIdFieldName;
Android
For standard sync up targets:
Create your target with one of these constructors:
1public SyncUpTarget(List<String> createFieldlist, List<String> updateFieldlist, 
2    String idFieldName, String modificationDateFieldName, 
3    String externalIdFieldName)
1public BatchSyncUpTarget(List<String> createFieldlist, List<String> updateFieldlist, 
2    String idFieldName, String modificationDateFieldName, 
3    String externalIdFieldName)
For parent-child sync up targets:
Pass a non-nil value to the externalIdFieldName parameters of these factory methods (new in Mobile SDK 9.0):
1// From ParentInfo.java
2public ParentInfo(String sobjectType, String soupName, String idFieldName, 
3    String modificationDateFieldName, String externalIdFieldName)
1// From ChildrenInfo.java
2public ChildrenInfo(String sobjectType, String sobjectTypePlural, String soupName, 
3    String parentIdFieldName, String idFieldName, 
4    String modificationDateFieldName, String externalIdFieldName)