I've gone through and duplicate this error several times. So I've
documented my workflow below and provided code for all major methods
along the path.:
1. Load page with all items in a Group (starting with none).
2. Add a unique item, works fine, one added to cache (Testing)
3. Add another unique item, still fine, one added to cache (Testing 2)
4. Add a duplicate item, business logic skips save method and shows
error (Testing 2)
5. Add another duplicate item, business logic skips save method and
shows error (Testing 2)
6. Add another unique item (Testing 3), cache now contains two copies
of second item added (Testing 2)
7. Attempt to add three duplicates of Testing 3.
8. Add another unique item (Testing 4), cache now contains four copies
of Testing 3.
At the end of all of this the data output from the cache looks like this:
ID Label
7 Testing
8 Testing 2
0 Testing 2
9 Testing 3
0 Testing 3
0 Testing 3
0 Testing 3
10 Testing 4
The data in the database however, looks like this:
7 Testing 7/20/2008 8:38:37 AM
8 Testing 2 7/20/2008 8:38:59 AM
9 Testing 3 7/20/2008 8:40:11 AM
10 Testing 4 7/20/2008 8:41:23 AM
Now as far as my code works, I'm using a cfwindow to add via ajax
using the following code in the ajax/additem action:
<cffunction name="addItem" access="public" returntype="void" output="false">
<cfargument name="Event" type="coldbox.system.beans.requestContext">
<cfset var rc = Event.getCollection() />
<!--- Pass the group ID in in order to assign the item to the proper group --->
<cfset rc.Item =
variables.objectFactory.getBean("ItemService").getItem(rc.GroupID, 0)
/>
<!--- Even if a blank object came back, be sure to set the group ID
correctly --->
<cfset rc.Item.setParentGroup(variables.objectFactory.getBean("GroupService").getGroup(Session.UserID,
rc.GroupID)) />
<cfset rc.Success = False />
<cfif IsDefined("rc.do") AND rc.do EQ "additem">
<cfset LOCAL.errors = ArrayNew(1) />
<!--- Populate User with data --->
<cfset getPlugin("beanFactory").populateBean(rc.Item) />
<cfset LOCAL.result =
variables.objectFactory.getBean("ItemService").save(rc.Item) />
<cfif LOCAL.result.results>
<cfset getPlugin("messagebox").setMessage(type="info",
message="Item Added!") />
<cfset rc.Success = True />
<cfelse>
<cfset getPlugin("messagebox").setMessage(type="error", message=
ArrayToList(LOCAL.result.errors, "<br />")) />
</cfif>
</cfif>
<cfset Event.setView("ajax/additem") />
</cffunction>
So it looks like the objects are getting added to the groups Items
cache even if they haven't been saved, which doesn't seem right to
me... I would think that only saved data should be persisted into the
cache. What can I do to rectify this problem?
Dan
Thanks for the catch, but unfortunately that doesn't fix the issue...
This is definitely at the Transfer level since it's ending up in the
Transfer cache. I went back through the code flow and ensured that I
hadn't left any other scopes un-vared and I get the exact same
behavior. Unsaved child items showing up in the parent cached object.
Dan
<cffunction name="save" access="public" returntype="struct" output="false">
<cfargument name="object" type="any" required="true" />
<cfset var LOCAL = StructNew() />
<cfset var validateData = "" />
<cfset var retVal = structnew()>
<cfset retVal.results = false />
<cfset retVal.message = "Invalid Request." />
<cfset retVal.messageType = "error" />
<cfset validateData = Arguments.object.validate() />
<cfif validateData.results>
<!--- save new bean data to db --->
<cfset variables.oTransfer.save(Arguments.object) />
<cfset retVal.results = true />
<cfset retVal.message = "Item Saved" />
<cfset retVal.messageType = "info" />
<cfelse>
<cfset retVal.errors = validateData.errors />
</cfif>
<cfreturn retVal />
</cffunction>
Dan
Matt is correct that you could removeParentGroup to fix the issue, but
another option would be to use a cloned object. This is precisely
what the clone() method is for. So instead of ItemService.getItem()
returning an actual Transfer object, have it return a clone of the
Transfer Object. Then your changes will not be reflected in the cache
until you actually save the object. This also prevents another user
from seeing the "bad data" in the cache between the time that you call
setParentGroup() and decide whether or not to save the object.
Bob
--
Bob Silverberg
www.silverwareconsulting.com
<!--- Pass the group ID in in order to assign the item to the proper group --->
<cfset rc.Item =
variables.objectFactory.getBean("ItemService").getItem(rc.GroupID,
0).Clone() />
<!--- Even if a blank object came back, be sure to set the group ID
correctly --->
<cfset rc.Item.setParentGroup(variables.objectFactory.getBean("GroupService").getGroup(Session.UserID,
rc.GroupID).Clone()) />
I'm getting a clone of the item, and then assigning it to a clone of
it's parent group, and all is well on save and errors.
Thanks,
Dan
http://dansshorts.com/?day=7/21/2008#blog368
Dan