The attached patch fixes this problem.
Implementation: If an object such as "Item" is deleted, it checks all
objects which it references (like Container), and gets each of these
objects to remove it from any list attributes they might have.
It would be great if someone (Geoff?) could apply this to CVS.
peace,
Jason
-----Forwarded Message-----
From: Jason Hildebrand <[EMAIL PROTECTED]>
To: webware-discuss <[EMAIL PROTECTED]>
Subject: problem deleting MiddleKit objects
Date: 20 Mar 2002 15:39:17 -0600
I'm having a problem deleting a MK object which is a member of a list.
Assume the following model:
Class Attribute Type
-------------------------------------
Item
container Container
name string
Container
name string
items list of Item
Now suppose there are two instances of Item (Item.1 and Item.2), one
instance of container (Container.1) and both Items are contained in
Container.1. That is, Item.1.container() == Item.2.container() ==
Container.1 (please excuse the abuse of notation).
Now I do something like:
c = store.fetchObject( 'Container', 1 )
items = c.items()
print len(items) # should be two
# delete one of the items
store.deleteObject( items[0] )
store.saveChanges()
print len( c.items() ) # should be one, but is still two
The reason is that the Container object caches its list of Items
internally as self._items, but after the Item is deleted, it doesn't
know to refresh its list. So, short of calling store.clear() to toss
out all cached objects (or restarting the app server), I can't convince
Container.1 that it now contains only one Item. If I try to reference
the "ghost" Item, I get a dangling reference error (which is correct).
Is this simply a matter of MiddleKit not being complete? Or is this
problem somehow unique to me?
After spending a considerable amount of time going through the MK
source, I suspect the former. If this is the case, I'll take a crack at
implementing the correct behaviour (now that I finally grok what's going
on, it doesn't seem too difficult to fix).
I didn't notice this problem until recently, since I was instantiating
a new store on every request (which is dumb). Now I have one global
store, which is the way (I think) MiddleKit was intended to be used
(although the docs don't really say much about this -- it would be good
to add some of these "big picture" assumptions to the user guide).
Cheers,
Jason
diff -r -u Webware/MiddleKit/Run/MiddleObject.py /home/jdhildeb/projects/Webware/MiddleKit/Run/MiddleObject.py
--- Webware/MiddleKit/Run/MiddleObject.py Fri Mar 15 16:07:51 2002
+++ /home/jdhildeb/projects/Webware/MiddleKit/Run/MiddleObject.py Wed Mar 27 11:01:30 2002
@@ -3,6 +3,8 @@
import ObjectStore
import sys, types
from MiddleKit.Core.ObjRefAttr import ObjRefAttr
+from MiddleKit.Core.ListAttr import ListAttr
class MiddleObject(NamedValueAccess):
"""
@@ -152,6 +154,31 @@
allAttrs[key] = getattr(self, attrName)
return allAttrs
+ def removeObjectFromListAttrs(self,object):
+ """
+ Removes object from any list attributes that this instance might have.
+ This is used if the object is deleted, so we don't dangling references.
+ """
+ for attr in self.klass().allAttrs():
+ if isinstance( attr, ListAttr ):
+ if object in self.valueForAttr(attr):
+ #print '%s: removing list reference to %s' % ( str(self), str(object) )
+ attrName = '_' + attr.name()
+ delattr(self,attrName)
+ setattr(self,attrName,None)
+
+ def updateReferencingListAttrs(self):
+ """
+ Checks through all object references, and asks each referenced
+ object to remove ourself from any list attributes that they
+ might have.
+ """
+ for attr in self.klass().allAttrs():
+ if isinstance( attr, ObjRefAttr ):
+ obj = self.valueForAttr(attr)
+ if obj:
+ obj.removeObjectFromListAttrs(self)
+
def backObjRefAttrs(self):
"""
Returns a list of all ObjRefAttrs in the given object model that can
diff -r -u Webware/MiddleKit/Run/ObjectStore.py /home/jdhildeb/projects/Webware/MiddleKit/Run/ObjectStore.py
--- Webware/MiddleKit/Run/ObjectStore.py Fri Mar 15 16:04:48 2002
+++ /home/jdhildeb/projects/Webware/MiddleKit/Run/ObjectStore.py Thu Mar 21 09:44:56 2002
@@ -252,6 +252,7 @@
if not checkOnly:
self.willChange()
self._deletedObjects.append(object)
+ object.updateReferencingListAttrs()
del self._objects[object.key()]