2

Based on the documentation LastSyncDate can be used as a safeguard to ensure that when someone else modified Apex Class in SFDC you do not accidentally overwrite those changes using your older local version.

Tooling API documentation states following about LastSyncDate field

When you deploy a MetadataContainer, this value is compared with the LastModifiedDate of the underlying Apex class. If LastSyncDate is older than LastModifiedDate, the deployment fails with an error.

If I am reading it right then I shall include (set) LastSyncDate on ApexClassMember every time when I deploy that ApexClassMember as part of MetadataContainer. However if I specify any value of LastSyncDate and then I always get this error message:

Unable to create/update fields: LastSyncDate. Please check the security settings of this field and verify that it is read/write for your profile or permission set.

Obviously this tells that I am trying to update the field which can only be Filtered or Sorted, but other than directly setting LastSyncDate on ApexClassMember I can not figure out any other way to provide LastSyncDate as part of my deployment package.

(Using SOAP version of Tooling API v28)
Here is the sequence of steps (ignore the syntax):
//assuming I have created ApexClass previously and now have its Id, let’s call it “objectId

  1. Create Metadata container (this gives us containerId)
  2. Instantiate ApexClassMember like so

    member = new ApexClassMember ()
    member.setContentEntityId(objectId)
    member.setBody(someClassBody)
    member.setMetadataContainerId(containerId)

  3. member.setLastSyncDate(someDate)
  4. Post ApexClassMember to SFDC
    sfdcToolingConnection.create(member)
If I skip step 3 then class body update succeeds, but if I include step 3 then system always returns the above mentioned error.

I am sure I am doing something wrong, but cannot figure out what this may be. Extensive googling did not return any examples of LastSyncDate usage in any shape or form.

Any hints will be very much appreciated.

3

LastSyncDate is not for manual setting. This field used in Metadata container to compare the time between components updated by two processes.

When you deploy component by metadatacontainer it compares the component with last sync date, if some one from other side updated the same component before you than its last modified date will be newer than your sync date and deployment will fail.

LastSyncDate and LastModifiedDate will be equal if you update some component by Tooling API. using ApexClassMember. Now if another user changed the same class from browser, after that you tried to sync by Tooling API, in that case deployment will fail as LastModifiedDate is newer than LastSyncDate.

Reference not saying to set LastSyncDate it get set automatically as your sync by Tooling API completes. It is used internally to prevent writing old code and losing the new one.

  • Just so I am clear - as long as I (via Tooling API) use the same instance of MetadataContainer (i.e. do not delete and re-create it again) system should prevent me from pushing ApexClassMember if ApexClass referenced by ApexClassMember has been updated by someone else (e.g. via SFDC web interface)? Did you get you right? – gaiser Sep 25 '13 at 20:20
  • looks like I got your explanation wrong. Tried the following: 1. User A (tooling api) - update ClassA (keep MetadataContainer);.. 2. User B (web interface) - modify ClassA (changed method name);.. 3. User A (tooling api) and previously saved MetadataContainer.id - update ClassA; ... Result: update successful, changes done by "User B" lost, Tooling API did not stop User A from updating ClassA. ... If this is expected behaviour then what do I need to do in Tooling API to make system stop me from updating a Class modified by someone else since my previous update via Tooling API? – gaiser Sep 26 '13 at 9:08
  • Sorry for the crappy comment formatting above, stackexchange won't allow me to format it properly. – gaiser Sep 26 '13 at 9:14
  • I copied this line from Tooling API ref: "The date and time that this ApexClassMember Body was replicated from the underlying Apex class. When you deploy a MetadataContainer, this value is compared with the LastModifiedDate of the underlying Apex class. If LastSyncDate is older than LastModifiedDate, the deployment fails with an error. " This should not happen if lastmodified date is newer that lastsyncdate. @gaiser – Ashwani Sep 26 '13 at 9:20
  • Taking that results of my testing "disagree" with the documentation which you quoted above I can think of one of three options: (A) documentation is wrong; (B) Tooling API does not behave as documentation suggests (a bug?); (C) There is a problem with my test.... I have checked, double and triple checked my test code, it seems okay, so I am leaning towards A or B.... I would love to see a working example which fails deployment when LastModified date is newer that LastSyncDate. You do not happen to know where I can find such an example @responsive ? – gaiser Sep 26 '13 at 11:16
3

This was too long for a comment, so posting as an answer with some of the mentioned information from the other post.

Reference not saying to set LastSyncDate it get set automatically as your sync by Tooling API completes. It is used internally to prevent writing old code and losing the new one.

Correct. This is the intended function.

(B) Tooling API does not behave as documentation suggests (a bug?);

Yes, there is a bug that prevents this from working. It was fixed in Spring'14, so if you are in a DE org this will still fail. I don't think there is a known issue posted.

In Spring'14, you should be able to go through your process:

  1. Update a container (will assign the LastModifiedDate of class to the LastSyncDate of container).
  2. Update the class through the UI.
  3. Deploy container (deploy will fail).

Note however, that the deploy will go through if you update the container with old source after the class has been updated. For example:

  1. Create a container with the source from a class
  2. Update the class through the UI.
  3. Update the container with new source based on the old source from the container (now the LastSyncDate will be from the LastModifiedDate from 2.)
  4. Deploy container (deploy will succeed)

It works that way so when the first flow hits the error, it can pull the updated source, merge them in the existing container, and deploy the updated changes. In other words, it is giving the power to the developer to handle that case.

I personally think that the LastSyncDate should only be set when the container is created, and updatable by the user. This would allow for the previous flow, but instead the deploy would fail. Then the developer will need to either:

  • Update the LastSyncDate to allow the container to override the class.
  • Create a new container, which would have a similar result unless the source was pulled from the updated class.

I would love to hear what your doing with the Tooling API.

  • thank you for your detailed answer. I may be missing the point of MetadataContainer, have just tested my old gist against Spring 14 Sandbox and the test still fails. My goal is to update Apex Class body with conflicts check in as little API calls as possible, see next comment for the sequence I am trying to achieve. – gaiser Mar 6 '14 at 10:24
  • Here is the sequence: 1) Create class MyClass; 2) Update MyClass as part of MetadataContainer, 3) some time later update MyClass via Web UI; 4) come back next day, change local MyClass code and send it to SFDC (re-using Id of my MetadataContainer) and get ERROR because my local version of MyClass is older than the one in SFDC. Is this supposed to be possible with Tooling API? Right now I am having to store LastModified date locally and query SFDC for current LastModifiedDate of MyClass before updating it, to make sure that my local version is not out of date. – gaiser Mar 6 '14 at 10:27
  • @gaiser, did you find a good way to solve this? i encountered this issue and found the lastsyncdate is useless for checking conflict. – Allen Li Jul 2 '15 at 11:44
  • @AllenLi, you have to store LastModified date locally after each deployment and query SFDC for current LastModifiedDate of a Class/Page/Trigger before updating it. Same as Metadata API - Tooling API does not provide any means to shorten this sequence and reduce number of calls. – gaiser Jul 2 '15 at 15:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.