The ColdFusion application uses a CFC to represent the data being exchanged and synchronized. For example, you could have an ORM employee component with a structure as follows:

<cfcomponent persistent="true" displayname="EMP">
<cfproperty name="id" type="numeric" fieldtype="id" generator="native">
<cfproperty name="firstName" type="string">
<cfproperty name="lastName" type="string">
...
<cfproperty name="countryCode" type="string">
</cfcomponent>

You can also use a traditional non-ORM CFC. In this case, the Fetch and Sync Methods use the cfquery tag and related tags and function for database operations.
To manage interactions with the AIR application and keep the data synchronized, ColdFusion application uses a component called the SyncManager. The SyncManager implements the CFIDE.AIR.ISyncManager interface. The component has two functions:

  • A fetch function that the AIR application calls to get data from ColdFusion. This function is not part of the ISyncManager interface, but is required. The function can have any arbitrary name, but is called fetch by convention.
  • A sync function that the AIR application calls to synchronize the ColdFusion and AIR data sources when the application updates or changes data. This function takes three parameters:
  • operations An array of operations to perform INSERT, UPDATE, or DELETE.
  • clientObjects An array of objects, where each item in the array represents the client's current view of the data to be synchronized.
  • originalObjects An array of objects, each item in this Array represents the corresponding original data from the server (if any), such as an existing employee record that a user is updating. For an INSERT operation, this object is null. For a DELETE operation, this object is normally the same as the current data.
    Incase of Conflict during Sync process, the sync function returns to the AIR client an Array of "CFIDE.AIR.Conflict.cfc" objects. Each of this Conflict object consists of a single serverObject element. The sync function sets the element to equal the server copy of the record that is in conflict. The client application can then handle the conflict as described in Conflict management.

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 serverobjectproperty 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 KeepServerObjectmethod 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>

This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License  Twitter™ and Facebook posts are not covered under the terms of Creative Commons.

Legal Notices   |   Online Privacy Policy