Mini-Tutorial: Conflict Detection

The following mini-tutorial demonstrates how merge modes affect save operations under various circumstances. It takes the form of an extended example within an HTML context.

  1. Set up the necessary caches:

    1var cache = new Force.StoreCache(soupName);
    2var cacheForOriginals = new Force.StoreCache(soupNameForOriginals);
    3var Account = Force.SObject.extend({
    4  sobjectType: "Account",
    5  fieldlist: ["Id", "Name", "Industry"],
    6  cache: cache,
    7  cacheForOriginals: cacheForOriginals,
    8});
  2. Get an existing account:

    1var account = new Account({Id:<some actual account id>});
    2account.fetch();
  3. Let’s assume that the account has Name:“Acme” and Industry:“Software”. Change the name to “Acme2.”

    1Account.set("Name", "Acme2");
  4. Save to the server without specifying a merge mode, so that the default “overwrite” merge mode is used:

    1account.save(null);

    The account’s Name is now “Acme2” and its Industry is “Software” Let’s assume that Industry changes on the server to “Electronics.”

  5. Change the account Name again:

    1Account.set("Name", "Acme3");

    You now have a change in the cache (Name) and a change on the server (Industry).

  6. Save again, using “merge-fail-if-changed” merge mode.

    1account.save(null,
    2   {mergeMode: "merge-fail-if-changed", error: function(err) {
    3   // err will be a map of the form:
    4   // {base:…, theirs:…, yours:…,
    5   // remoteChanges:["Industry"], localChanges:["Name"],
    6   // conflictingChanges:[]}
    7});

    The error callback is called because the server record has changed.

  7. Save again, using “merge-fail-if-conflict” merge mode. This merge succeeds because no conflict exists between the change on the server and the change on the client.

    1account.save(null, { mergeMode: "merge-fail-if-conflict" });

    The account’s Name is now “Acme3” (yours) and its Industry is “Electronics” (theirs). Let’s assume that, meanwhile, Name on the server changes to “NewAcme” and Industry changes to “Services.”

  8. Change the account Name again:

    1Account.set("Name", "Acme4");
  9. Save again, using “merge-fail-if-changed” merge mode. The error callback is called because the server record has changed.

    1account.save(null, {mergeMode: "merge-fail-if-changed", error: function(err) {
    2   // err will be a map of the form:
    3   // {base:…, theirs:…, yours:…,
    4   // remoteChanges:["Name", "Industry"],
    5   // localChanges:["Name"], conflictingChanges:["Name"]}
    6});
  10. Save again, using “merge-fail-if-conflict” merge mode:

    1account.save(null, {
    2  mergeMode: "merge-fail-if-changed",
    3  error: function (err) {
    4    // err will be a map of the form:
    5    // {base:…, theirs:…, yours:…,
    6    // remoteChanges:["Name", "Industry"],
    7    // localChanges:["Name"], conflictingChanges:["Name"]}
    8  },
    9});

    The error callback is called because both the server and the cache change the Name field, resulting in a conflict:

  11. Save again, using “merge-accept-yours” merge mode. This merge succeeds because your merge mode tells the save() function which Name value to accept. Also, since you haven’t changed Industry, that field doesn’t conflict.

    1account.save(null, { mergeMode: "merge-accept-yours" });

    Name is “Acme4” (yours) and Industry is “Services” (theirs), both in the cache and on the server.

We've Moved

Welcome to the new home of the Mobile SDK Developer Guide! For now, the Japanese guide can be found in PDF form.