Server-Side notes

  • When the sync function performs a DELETE operation, it gets the primary key ID from the OriginalObject of the Sync method, as the ClientObject is NULL. For update and insert operations, use the ClientObject key value.

  • When you do an INSERT operation, the CFC checks whether the OriginalObject parameter of the sync method is a simple value, as in the following code:
    {NOT IsSimpleValue(OriginalObject)}
    In an INSERT operation, OriginalObject passed to the Sync function is null. So if you attempt to retrieve any of its properties, you get a Method NOT Found error. For Example, OriginalObject.GetID results in a Method GetID() not found error. So, for Insert operation, use ClientObject to access various fields.
  • While a ColdFusion application can use cfquery to directly manage the database, most AIR applications are expected to use the ORM feature. The discussion here uses ColdFusion ORM for server-side data management.

  • You may see the following kind of error message if you are using ColdFusion 8 Remoting with AIR offline applications, which have server side "Sync" method using ORM EntitySave()/EntityDelete() methods.
    Error handling message: flex.messaging.MessageException: Unable to invoke CFC - a different object with the same identifier value was already associated with the session: [address#1]. 
    Root cause:org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [address#1]

    You may also encounter this error with ColdFusion 9 Remoting but only for EntityDelete method.

    To resolve this sort of error, call your EntitySave/EntityDelete method in following way in "Sync" method.

    <cfif operation eq "INSERT" OR operation eq "UPDATE"> 
        <cfset obj = ORMGetSession().merge(clientobject)> 
        <cfset EntitySave(obj)> 
    <cfelseif operation eq "DELETE"> 
        <cfset obj = ORMGetSession().merge(originalobject)> 
        <cfset EntityDelete(obj)> 
    </cfif>
  • In case of a conflict, the sync function returns an array of "CFIDE.AIR.Conflict" objects to the client. There are four properties a conflict object can have: operation,serverobject,clientobject,originalobject.

    The serverobject property of the conflict object must be a user-defined CFC type that represents the server-side database table. The following example generates a conflict object with a valid ServerObject property of type employee.cfc, which represents the Employee table:

    <cfset serverobject = EntityLoadByPK("employee",originalobject.getId())> 
    <cfset conflict = CreateObject("component","CFIDE.AIR.conflict")> 
    <cfset conflict.serverobject = serverobject> 
    <cfset conflict.clientobject = clientobject> 
    <cfset conflict.originalobject = originalobject> 
    <cfset conflict.operation = operation> 
    <cfset conflicts[conflictcount++] = conflict> 
    <cfreturn conflicts>
    If you are using ColdFusion ORM, you can replace the preceding example with the following code.
    <cfset conflict = CreateObject("component","CFIDE.AIR.Conflict") 
    <cfset serverobject = EntityLoadByPK("employee",#res.IDENTITYCOL#)> 
    <cfset conflict.SetServerobject(serverobject)>
  • When an AIR client with stale data tries to update an already deleted record from the database, server throws the conflict, and the client's conflict handle, which has the KeepAllServerObjects or KeepServerObject method accepts the changes from the server. However, the client method does not delete the stale record, which no longer exists in the server database, from the client database.

    To prevent this issue: The serverObject property of the conflict object returned by the server must be null, if the record that the client requests for updating is no longer in the database. For example:

    <cfset serverobject = EntityLoadByPK("employee",originalobject.getId())> 
    <!----If the operation is INSERT, serverObject is also NULL.hence NEQ condition----> 
    <cfif not isdefined('serverobject') and operation NEQ "INSERT" > 
    <cflog text="CONFLICT::SERVER OBJECT NOT FOUND, RECORD MAY BE DELETED ALREADY"> 
    <cfset conflict = CreateObject("component","CFIDE.AIR.conflict")> 
    <cfset conflict.clientobject = clientobject> 
    <cfset conflict.originalobject = originalobject> 
    <cfset conflict.operation = operation> 
    <cfset conflicts[conflictcount++] = conflict> 
    <cfcontinue> 
    </cfif>