[Modeling-cvs] ProjectModeling/Modeling DatabaseContext.py,1.17,1.18 CHANGES,1.136,1.137
Status: Abandoned
Brought to you by:
sbigaret
|
From: <sbi...@us...> - 2003-07-28 06:15:19
|
Update of /cvsroot/modeling/ProjectModeling/Modeling
In directory sc8-pr-cvs1:/tmp/cvs-serv5634
Modified Files:
DatabaseContext.py CHANGES
Log Message:
Removed the constraint on to-many relationships for which an inverse to-one
relationship had to be defined.
Details: recordChangesInEditingContext() refactored,
recordUpdateForObject() implemented,
Index: DatabaseContext.py
===================================================================
RCS file: /cvsroot/modeling/ProjectModeling/Modeling/DatabaseContext.py,v
retrieving revision 1.17
retrieving revision 1.18
diff -C2 -d -r1.17 -r1.18
*** DatabaseContext.py 16 Jul 2003 19:16:00 -0000 1.17
--- DatabaseContext.py 28 Jul 2003 06:15:15 -0000 1.18
***************
*** 21,25 ****
#
#-----------------------------------------------------------------------------
!
"""
--- 21,25 ----
#
#-----------------------------------------------------------------------------
! from __future__ import nested_scopes
"""
***************
*** 81,84 ****
--- 81,87 ----
from mx.DateTime import DateFrom
+ import sys
+ #trace=lambda msg: sys.stderr.write(str(msg)+'\n')
+
# Framework
from Database import DistantPastTimeInterval, GeneralDatabaseException
***************
*** 304,307 ****
--- 307,311 ----
# Set of DatabaseOperation
self._dbOperations=[]
+ self._pending_dbOperations={} # gid -> DatabaseOperation
# local cache for snapshots, initialized in prepareForSaveWithCoordinator
***************
*** 486,489 ****
--- 490,494 ----
"""
+ See SnapshotsHandling/recordSnapshotForGlobalID()
"""
return self.__snapshots.recordSnapshotForGlobalID(snapshot, aGlobalID)
***************
*** 492,495 ****
--- 497,501 ----
"""
+ See SnapshotsHandling.recordSnapshotForSourceGlobalID()
"""
return self.__snapshots.recordSnapshotForSourceGlobalID(aGlobalID)
***************
*** 498,501 ****
--- 504,508 ----
"""
+ See SnapshotsHandling.recordSnapshots()
"""
return self.__snapshots.recordSnapshots(snapshots)
***************
*** 505,508 ****
--- 512,516 ----
"""
+ See SnapshotsHandling.recordToManySnapshots()
"""
return self.__snapshots.recordToManySnapshots(snapshots)
***************
*** 510,517 ****
def recordUpdateForObject(self, aDatabaseObject, changes):
"""
! Unimplemented yet
"""
! self.__unimplemented__()
def registerChannel(self, aDBchannel):
"""
--- 518,619 ----
def recordUpdateForObject(self, aDatabaseObject, changes):
"""
! Called by the ObjectStoreCoordinator when an other DatabaseContext
! (including self) needs to forward changes on a given object --this can
! happen, for example, when a toMany relationship that has no inverse to-one
! relationship is modified in a given object 'obj1', because in this case
! the modification implies the modification of a foreign key stored in one
! or more objects 'obj<i>!=obj1'.
!
! This method is for internal use, you should not need to call it by
! hand. The following explanations are implementation details.
!
! DatabaseContexts are designed in such a way that it can receive such
! messages before or after recordChangesInEditingContext() has processed its
! own changes. More precisely, when calling this method on self,
! recordChangesInEditingContext() takes care to process all its changes
! (inserted, updated or deleted objects) before it may call this method.
!
! As a consequence:
!
! - if recordChangesInEditingContext() has not been called yet, it just
! stores the pending changes to be applied, by simply storing 'changes'
! in a pending database operation's newRow(). These changes will be then
! processed when recordChangesInEditingContext() is called.
!
! - otherwise, the behaviour depends on whether the method
! recordChangesInEditingContext() already created a database operation
! for the object. If it did, then this database operation is updated
! according to the supplied changes; otherwise a brand new database
! oeration is created and local snapshots are registered for the object.
!
! Parameters:
!
! aDatabaseObject -- the database object for which changes are notified
!
! changes -- a dictionary of {attributeName: value}
!
! See also: ObjectStoreCoordinator.forwardUpdateForObject()
! recordChangesInEditingContext()
"""
! #self.__unimplemented_()
! # search for DB OP TBD
! original_gid=object_gid=aDatabaseObject.globalID()
! if object_gid.isTemporary():
! object_gid=self.__temporaryGID_to_KeyGlobalID[object_gid]
! trace('recordUpdateForObject() aDatabaseObject: %s gid: %s changes: %s'%(aDatabaseObject, object_gid, changes))
! dbOp=None
!
! if not self._dbOperations:
! # recordChangesInEditingContext() not called yet: just store changes
! # for later use
! trace('recordUpdateForObject() CALLED BEFORE recordChangesInEditingContext()')
! entity=self._database.entityNamed(object_gid.entityName())
! dbOp=DatabaseOperation(object_gid, aDatabaseObject, entity)
! dbOp.setDatabaseOperator(DATABASE_UPDATE_OPERATOR)
! dbOp.setNewRow(changes)
! pendingDBops=self._pending_dbOperations.setdefault(object_gid, [])
! pendingDBops.append(dbOp)
! return
!
! # from this point on, we know recordChangesInEditingContext() was called:
! # we then either find the relevant dbOperation, or create our own
! #
! for op in self._dbOperations: # TBD optimize / filter et/ou acces par dict.
! if op.globalID() == object_gid:
! trace('recordUpdate() Found dbOp %s'%op)
! dbOp=op
! break
!
! if dbOp is None:
! trace('recordUpdate() Creating dbOp')
! entity=self._database.entityNamed(object_gid.entityName())
! dbOp=DatabaseOperation(object_gid, aDatabaseObject, entity)
! dbOp.setDatabaseOperator(DATABASE_UPDATE_OPERATOR)
! self._dbOperations.append(dbOp)
! toManyKeys=aDatabaseObject.toManyRelationshipKeys()
! snapshot=aDatabaseObject.snapshot()
! snapshot.update(changes)
! snapshot, toManySnapshots=\
! self._objectSnapshotToDBOperatorSnapshots(snapshot, object_gid,
! toManyKeys, entity)
! self.recordSnapshotForGlobalID(snapshot, object_gid)
! self.recordToManySnapshots({object_gid: toManySnapshots})
! dbOp.setNewRow(snapshot)
! trace('recordUpdate snapshot:%s dbOp.newRow():%s'%(snapshot, dbOp.newRow()))
! dbOp.recordToManySnapshots(toManySnapshots)
! if aDatabaseObject.globalID().isTemporary():
! dbOp.setDBSnapshot({})
! else:
! dbOp.setDBSnapshot(self.database().snapshotForGlobalID(object_gid))
+
+ else:
+ dbOp.newRow().update(changes)
+ trace('YYYYYYYYYYYYYYYY %s %s'%(object_gid,self.snapshotForGlobalID(object_gid)))
+ #self.recordSnapshotForGlobalID(dbOp.newRow(), object_gid)
+ new_row=dbOp.newRow()
+ trace('recordUpdateForObject(): new_row: %s'%new_row)
+
+
def registerChannel(self, aDBchannel):
"""
***************
*** 546,549 ****
--- 648,652 ----
def registerLockedObjectWithGlobalID(self, aGlobalID):
"""
+ Unimplemented
"""
***************
*** 645,649 ****
finalizeCommitChanges()
"""
! if not self.__isSavingChanges():
raise RuntimeError, "Invalid state: DatabaseContext isn't saving changes"
--- 748,752 ----
finalizeCommitChanges()
"""
! if not self.isSavingChanges():
raise RuntimeError, "Invalid state: DatabaseContext isn't saving changes"
***************
*** 683,687 ****
"""
! if not self.__isSavingChanges():
raise RuntimeError, "Invalid state: DatabaseContext isn't saving changes"
--- 786,790 ----
"""
! if not self.isSavingChanges():
raise RuntimeError, "Invalid state: DatabaseContext isn't saving changes"
***************
*** 706,712 ****
def handlesFetchSpecification(self, aFetchSpecification):
"""
! Searches the Database object for an entity named
! aFetchSpecification.entityName, returns 1/true if such an entity was
! found, 0/false otherwise.
"""
if self._database.entityNamed(aFetchSpecification.entityName()):
--- 809,816 ----
def handlesFetchSpecification(self, aFetchSpecification):
"""
! Tells whether the DatabaseContext is responsible for the fetch
! specification. A DatabaseContext is responsible for a fetch specification
! if the fetchSpec's entity is registered in the entities set managed by the
! dbContext.database()
"""
if self._database.entityNamed(aFetchSpecification.entityName()):
***************
*** 716,719 ****
--- 820,826 ----
def ownsGlobalID(self, aGlobalID):
"""
+ Tells whether the DatabaseContext is responsible for the object. A
+ DatabaseContext is responsible for an object if the global id's entity is
+ registered in the entities set managed by the dbContext.database()
"""
try:
***************
*** 727,730 ****
--- 834,840 ----
def ownsObject(self, anObject):
"""
+ Tells whether the DatabaseContext is responsible for the object. A
+ DatabaseContext is responsible for an object if the object's entity is
+ registered in the entities set managed by the dbContext.database()
"""
cd=ClassDescription.classDescriptionForObject(anObject)
***************
*** 753,757 ****
Raises 'RuntimeError' if the DatabaseContext is not saving changes.
"""
! if not self.__isSavingChanges():
raise RuntimeError, "Invalid state: DatabaseContext isn't saving changes"
--- 863,867 ----
Raises 'RuntimeError' if the DatabaseContext is not saving changes.
"""
! if not self.isSavingChanges():
raise RuntimeError, "Invalid state: DatabaseContext isn't saving changes"
***************
*** 762,765 ****
--- 872,879 ----
_adaptorOperations=[]
+ trace('performChanges: dbOps: %s'%self._dbOperations)
+ #import pprint
+ #pprint.pprint(self._dbOperations)
+
for dbOp in self._dbOperations:
# Simple: No locking, just operations
***************
*** 804,807 ****
--- 918,922 ----
ADAPTOR_INSERT_OPERATOR)
adOp.setChangedValues(databaseOperation.newRow())
+ trace('dbOptoAdOp: new row: %s'%databaseOperation.newRow())
return [adOp]
***************
*** 818,821 ****
--- 933,937 ----
rowDiffs=databaseOperation.rowDiffs()
if not rowDiffs:
+ trace('NO ROW DIFF %s'%databaseOperation)
return []
adOp=AdaptorOperation(databaseOperation.entity(),
***************
*** 893,900 ****
self.__temporaryGID_to_KeyGlobalID[gID]=newGid
def recordChangesInEditingContext(self):
"""
Second step being triggered by the ObjectStoreCoordinator when the latter
! was instructed to do save the changes made in an EditingContext.
The 'EditingContext' instance this method works with is the one supplied
when 'prepareForSaveWithCoordinator()' was called.
--- 1009,1093 ----
self.__temporaryGID_to_KeyGlobalID[gID]=newGid
+ def _recordChangesInEditingContext(self, gID, obj, dbOperator):
+ """
+ Called by recordChangesInEditingContext() for each inserted, updated and
+ deleted object it examines. This method is for internal use only, you
+ should not need to call it by hand.
+
+ This method creates the corresponding DatabaseOperation for the object,
+ adds it to the DatabaseContext's database operations. It also registers
+ the local snapshots for that objects (whose local snapshots will be passed
+ to the database() obect when changes are saved). It also examines any
+ pending DatabaseOperations that have been received by
+ recordUpdateForObject() before recordChangesInEditingContext() was called
+ (these changes were submitted by other DatabaseContexts). Last, it also
+ examines the resulting DatabaseOperation and set its operator to
+ DATABASE_NOTHING_OPERATOR if appropriate.
+
+ Parameters:
+
+ gID -- the globalID of the object, either temporary or not. If it is
+ temporary, it will be translated into the non-temporary GlobalID
+ the object will receive after it's been changed.
+
+ obj -- the object to register
+
+ dbOperator -- the database operator to be used for the created
+ DatabaseOperation
+
+ See also: _examineToManySnapshots()
+ """
+ entity=self.database().entityForObject(obj)
+
+ if dbOperator==DATABASE_INSERT_OPERATOR or gID.isTemporary():
+ # Build and use a regular (Key)GlobalID
+ gID=KeyGlobalID(entity.name(), self._pks_for_inserted_gIDs[gID])
+ else:
+ pass
+
+ #self.__temporaryGID_to_KeyGlobalID[tempGID]=gID
+ dbOp=DatabaseOperation(gID, obj, entity)
+ dbOp.setDatabaseOperator(dbOperator)
+ self._dbOperations.append(dbOp)
+
+ # Now for the snapshotting part
+ objSnapshot=obj.snapshot()
+ toManyKeys=obj.toManyRelationshipKeys()
+ snapshot, toManySnapshots=\
+ self._objectSnapshotToDBOperatorSnapshots(objSnapshot, gID,
+ toManyKeys, entity)
+
+ # get pending operations received by recordUpdateForObject()
+ pending_ops=self._pending_dbOperations.get(gID, [])
+ for pending_op in pending_ops:
+ snapshot.update(pending_op.newRow())
+ if pending_ops:
+ del self._pending_dbOperations[gID]
+
+ self.recordSnapshotForGlobalID(snapshot, gID)
+ self.recordToManySnapshots({gID: toManySnapshots})
+ dbOp.setNewRow(snapshot)
+ dbOp.recordToManySnapshots(toManySnapshots)
+
+ if dbOperator==DATABASE_INSERT_OPERATOR:
+ dbOp.setDBSnapshot({})
+ else:
+ dbOp.setDBSnapshot(self.database().snapshotForGlobalID(gID))
+
+ if dbOperator==DATABASE_UPDATE_OPERATOR:
+ # requires:
+ # dbOp.__dbSnapshot/setDBSnapshot + .__newRow/setNewRow
+ rowDiffs=dbOp.rowDiffs()
+ if not rowDiffs:
+ trace('recordChangesInEditingContext() ->NOTHING obj:%s gID:%s'%(obj, gID))
+ dbOp.setDatabaseOperator(DATABASE_NOTHING_OPERATOR)
+
+ trace('_recordChangesInEditingContext returning: %s, %s'%(gID, toManySnapshots))
+ return gID, toManySnapshots
+
def recordChangesInEditingContext(self):
"""
Second step being triggered by the ObjectStoreCoordinator when the latter
! was instructed to save the changes made in an EditingContext.
The 'EditingContext' instance this method works with is the one supplied
when 'prepareForSaveWithCoordinator()' was called.
***************
*** 905,909 ****
persistent,
! - it also registered every changed objects into the local snapshotting
table. **IMPORTANT**: the local snapshotting mechanism does not have
any references to TemporaryGlobalID objects: new objects are detected
--- 1098,1102 ----
persistent,
! - it also registers every changed objects into the local snapshotting
table. **IMPORTANT**: the local snapshotting mechanism does not have
any references to TemporaryGlobalID objects: new objects are detected
***************
*** 919,922 ****
--- 1112,1116 ----
commitChanges(), rollbackChanges(),
EditingContext.saveChanges()
+ recordUpdateForObject()
Raises 'RuntimeError' if the DatabaseContext is not saving changes.
***************
*** 932,1008 ****
complete discussion on this topic.
! See also: DatabaseOperation
"""
! if not self.__isSavingChanges():
raise RuntimeError, "Invalid state: DatabaseContext isn't saving changes"
for tempGID in self._inserted_gIDs:
! object=self._editingContext.objectForGlobalID(tempGID)
! entity=self.database().entityForObject(object)
! # Build and use a regular (Key)GlobalID
! gID=KeyGlobalID(entity.name(), self._pks_for_inserted_gIDs[tempGID])
! #self.__temporaryGID_to_KeyGlobalID[tempGID]=gID
! dbOp=DatabaseOperation(gID, object, entity)
! dbOp.setDatabaseOperator(DATABASE_INSERT_OPERATOR)
! self._dbOperations.append(dbOp)
! # Now for the snapshotting part
! objSnapshot=object.snapshot()
! toManyKeys=object.toManyRelationshipKeys()
! snapshot, toManySnapshots=\
! self._objectSnapshotToDBOperatorSnapshots(objSnapshot, gID,
! toManyKeys, entity)
! self.recordSnapshotForGlobalID(snapshot, gID)
! self.recordToManySnapshots({gID: toManySnapshots})
! dbOp.setNewRow(snapshot)
! dbOp.recordToManySnapshots(toManySnapshots)
! dbOp.setDBSnapshot({})
! for gID in self._updated_gIDs:
! object=self._editingContext.objectForGlobalID(gID)
! entity=self.database().entityForObject(object)
! dbOp=DatabaseOperation(gID, object, entity)
! dbOp.setDatabaseOperator(DATABASE_UPDATE_OPERATOR)
! self._dbOperations.append(dbOp)
! toManyKeys=object.toManyRelationshipKeys()
! objSnapshot=object.snapshot()
! snapshot, toManySnapshots=\
! self._objectSnapshotToDBOperatorSnapshots(objSnapshot, gID,
! toManyKeys, entity)
! self.recordSnapshotForGlobalID(snapshot, gID)
! self.recordToManySnapshots({gID: toManySnapshots})
! dbOp.setNewRow(snapshot)
! dbOp.recordToManySnapshots(toManySnapshots)
! dbOp.setDBSnapshot(self.database().snapshotForGlobalID(gID))
for gID in self._deleted_gIDs:
! object=self._editingContext.objectForGlobalID(gID)
! entity=self.database().entityForObject(object)
! dbOp=DatabaseOperation(gID, object, entity)
! dbOp.setDatabaseOperator(DATABASE_DELETE_OPERATOR)
! self._dbOperations.append(dbOp)
! # __TBD is this needed??
! toManyKeys=object.toManyRelationshipKeys()
! snapshot=object.snapshot()
! snapshot, toManySnapshots=\
! self._objectSnapshotToDBOperatorSnapshots(snapshot, gID,
! toManyKeys, entity)
! self.recordSnapshotForGlobalID(snapshot, gID)
! self.recordToManySnapshots({gID: toManySnapshots})
! dbOp.setNewRow(snapshot)
! dbOp.recordToManySnapshots(toManySnapshots)
! dbOp.setDBSnapshot(self.database().snapshotForGlobalID(gID))
def _objectSnapshotToDBOperatorSnapshots(self, objectSnapshot,
globalID, toManyKeys, entity):
"""
Internally used to convert a CustomObject.snapshot() to a snapshot a
! DatabaseOperator can fed fed with.
Returns a tuple of two elements:
--- 1126,1273 ----
complete discussion on this topic.
! This method also always add a fake DatabaseOperation to its own set, whose
! operator is DATABASE_NOTHING_OPERATOR and whose globalID, object and
! entity all equals to the string 'fake' --this is used by
! recordUpdateForObject(), see this method for a complete discussion on
! this.
!
! See also: DatabaseOperation,
! _recordChangesInEditingContext(), _examineToManySnapshots()
"""
! if not self.isSavingChanges():
raise RuntimeError, "Invalid state: DatabaseContext isn't saving changes"
+ # recordUpdateForObject() uses self._dbOperations to check whether
+ # we've been already called, so we add a fake dbOperation making NOTHING
+ # See recordUpdateForObject() docstring for details
+ fake_dbOp=DatabaseOperation('fake', 'fake', 'fake')
+ fake_dbOp.setDatabaseOperator(DATABASE_NOTHING_OPERATOR)
+ self._dbOperations.append(fake_dbOp)
+
+ # this holds tomany snapshots, returned by _recordChangesInEditingContext()
+ # for use by the last phase, when invoking _examineToManySnapshots()
+ toManySnaps={}
+
for tempGID in self._inserted_gIDs:
! obj=self._editingContext.objectForGlobalID(tempGID)
! toManySnaps[tempGID]=self._recordChangesInEditingContext(tempGID, obj, DATABASE_INSERT_OPERATOR)
! for gID in self._updated_gIDs:
! obj=self._editingContext.objectForGlobalID(gID)
! toManySnaps[gID]=self._recordChangesInEditingContext(gID, obj, DATABASE_UPDATE_OPERATOR)
!
! for gID in self._deleted_gIDs:
! obj=self._editingContext.objectForGlobalID(gID)
! toManySnaps[gID]=self._recordChangesInEditingContext(gID, obj, DATABASE_DELETE_OPERATOR)
!
! # process the remaining pending databaseOperation
! for pending_gid, pending_dbOps in self._pending_dbOperations.items():
! trace('recordUpdate(): processing pending gid: %s'%pending_gid)
! assert(not pending_gid.isTemporary()) ##
! obj=self._editingContext.objectForGlobalID(gid)
! toManySnaps[gID]=self._recordChangesInEditingContext(pending_gid, obj, DATABASE_UPDATE_OPERATOR)
! self._updated_gIDs.append(pending_gid)
!
! assert(self._pending_dbOperations == {}) # reset
! # Forwards possible changes (to recordUpdateForObject()) at the end
! for tempGID in self._inserted_gIDs:
! obj=self._editingContext.objectForGlobalID(tempGID)
! self._examineToManySnapshots(obj,
! toManySnaps[tempGID][0],
! toManySnaps[tempGID][1])
! for gID in self._updated_gIDs:
! obj=self._editingContext.objectForGlobalID(gID)
! self._examineToManySnapshots(obj, gID, toManySnaps[gID][1])
for gID in self._deleted_gIDs:
! obj=self._editingContext.objectForGlobalID(gID)
! self._examineToManySnapshots(obj, gID, toManySnaps[gID][1])
!
! def _examineToManySnapshots(self, object, aGlobalID, toManySnapshots):
! """
! Examine the toMany snapshot computed by recordChangesInEditingContext()
! for an object, and takes the responsability to invoke
! ObjectStoreCoordinator.forwardUpdateForObject() for any object that should
! be notified of changes they couldn't be aware of yet. This is the case
! when an object modifies a to-many relationship which has no inverse: in
! this case we have to notify the added or removed objects that the foreign
! key storing the information for the to-many rel. should be changed.
!
! This method is for internal use, you should not need to call it by hand.
!
! Note: this method does NOT react to any modifications of to-many
! relationships which have an inverse to-one relationship defined in the
! model. It is the developer's responsability to maintain the consistency of
! the graph of objects hold by an EditingContext; when this is done, as
! expected, the added or removed objects have already been notified that
! something has changed and shouldn't be notified twice.
!
! Parameters:
!
! object -- the object to which the toManySnapshots belongs
!
! aGlobalID -- the object's non-temporary global id
!
! toManySnapshots -- the to-many snapshots to be examined
!
! """
! changes={}
! ec=self._editingContext
+ for key in toManySnapshots.keys():
+ rel=object.classDescription().entity().relationshipNamed(key)
+ assert(rel.isToMany())
+
+ # to-many rel
+ if rel.inverseRelationship():
+ continue
+ db_snap=self.database().snapshotForSourceGlobalID(aGlobalID, key)
+ if list(db_snap) == toManySnapshots[key]:
+ continue
+ trace('############### %s != %s'%(list(db_snap), toManySnapshots[key]))
+ inv_rel=rel.anyInverseRelationship()
+ added_gids=[gid for gid in toManySnapshots[key] if gid not in db_snap]
+ removed_gids=[gid for gid in db_snap if gid not in toManySnapshots[key]]
+ trace('ADDED: %s'% added_gids)
+ trace('REMOVED: %s'% removed_gids)
+ modified_gids=added_gids+removed_gids
+ ###
+ def forwardChangesToObjects(self, inv_rel, removed):
+ for join in inv_rel.joins():
+ src_attr=join.sourceAttributeName()
+ dst_attr=join.destinationAttributeName()
+ if removed:
+ changes[src_attr]=None
+ else:
+ changes[src_attr]=aGlobalID.keyValues()[dst_attr]
+ real_gid=gid
+ for g in self.__temporaryGID_to_KeyGlobalID.keys():
+ if self.__temporaryGID_to_KeyGlobalID[g]==gid:
+ real_gid=g
+ break
+
+ related_object=ec.faultForGlobalID(real_gid, ec)
+ trace('_examineToManySnapshots() related object: %s real_gid: %s'%(related_object, real_gid))
+ self._coordinator.forwardUpdateForObject(related_object, changes)
+ ###
+
+ for gid in added_gids:
+ forwardChangesToObjects(self, inv_rel, removed=0)
+
+ for gid in removed_gids:
+ forwardChangesToObjects(self, inv_rel, removed=1)
+
def _objectSnapshotToDBOperatorSnapshots(self, objectSnapshot,
globalID, toManyKeys, entity):
"""
Internally used to convert a CustomObject.snapshot() to a snapshot a
! DatabaseOperator can fed with.
Returns a tuple of two elements:
***************
*** 1048,1052 ****
#snap.update(self._pks_for_inserted_gIDs[globalID])
! # last, remove keys corresponding to a to-one relationship and
# replace them with the appropriate (source-)attributes' keys and values
for key in snap.keys():
--- 1313,1317 ----
#snap.update(self._pks_for_inserted_gIDs[globalID])
! # Remove keys corresponding to a to-one relationship and
# replace them with the appropriate (source-)attributes' keys and values
for key in snap.keys():
***************
*** 1072,1075 ****
--- 1337,1348 ----
for idx in range(len(srcAttrs)):
snap[srcAttrNames[idx]]=pkValues[rel.destinationAttributeForSourceAttribute(srcAttrs[idx]).name()]
+
+ # Last, check that all FKs are included, as expected
+ # It can happen that it is not the case when a toMany rel. has no inverse
+ # --> see test_EditingContext_Global_Inheritance,
+ # test: test_10_toMany_with_no_inverse__db_snapshot_is_correct()
+ for attr in entity.attributesNames():
+ snap.setdefault(attr, None)
+
return (snap, toManySnap)
***************
*** 1087,1091 ****
See also: commitChanges()
"""
! if not self.__isSavingChanges():
raise RuntimeError, "Invalid state: DatabaseContext isn't saving changes"
--- 1360,1364 ----
See also: commitChanges()
"""
! if not self.isSavingChanges():
raise RuntimeError, "Invalid state: DatabaseContext isn't saving changes"
***************
*** 1093,1112 ****
self._endTransaction()
- def recordUpdateForObject(self, anObject, aDictionaryOfChanges):
- """
- Unimplemented: for the moment being we assume that every relationship has
- an inverseRelationship defined in the model, and that the corresponding
- delete rules are *NOT* DELETE_NOACTION ; as a consequence,
- EditingContext.processRecentChanges() does the necessary to keep the graph
- of objects in sync with all the modifications that are made, hence there
- is no need to forward changes that couldnt have been noticed earlier
- (there cannot be one of these!)
- """
- #?defined in upper abstract class?#
- #?defined in upper abstract class?#
- #?defined in upper abstract class?#
- self.__unimplemented__()
- # update local snapshot
-
def valuesForKeys(self, keys, aDatabaseObject):
"""
--- 1366,1369 ----
***************
*** 1128,1132 ****
after commit or rollback).
! See also: __isSavingChanges()
"""
self._coordinator=None
--- 1385,1389 ----
after commit or rollback).
! See also: isSavingChanges()
"""
self._coordinator=None
***************
*** 1137,1140 ****
--- 1394,1398 ----
self._pks_for_inserted_gIDs={}
self._dbOperations=[]
+ self._pending_dbOperations={}
self.__snapshots=None
self.__channel.closeChannel()
***************
*** 1142,1149 ****
self.__temporaryGID_to_KeyGlobalID=None
! def __isSavingChanges(self):
"""
Tells whether the DatabaseContext is currently saving changes.
- (internal use)
See also: prepareForSaveWithCoordinator(), saveChangesInEditingContext(),
--- 1400,1406 ----
self.__temporaryGID_to_KeyGlobalID=None
! def isSavingChanges(self):
"""
Tells whether the DatabaseContext is currently saving changes.
See also: prepareForSaveWithCoordinator(), saveChangesInEditingContext(),
Index: CHANGES
===================================================================
RCS file: /cvsroot/modeling/ProjectModeling/Modeling/CHANGES,v
retrieving revision 1.136
retrieving revision 1.137
diff -C2 -d -r1.136 -r1.137
*** CHANGES 25 Jul 2003 15:39:03 -0000 1.136
--- CHANGES 28 Jul 2003 06:15:16 -0000 1.137
***************
*** 8,11 ****
--- 8,17 ----
--------------------------------------------------------
+ * Removed the constraint on to-many relationships for which an inverse
+ to-one relationship had to be defined.
+ Details: recordChangesInEditingContext() refactored,
+ recordUpdateForObject() implemented,
+ model StoreEmployees changed.
+
* Added Relationship.anyInverseRelationship() --plus entity Holidays in
test model StoreEmployees, with a toMany rel. Employee-->Holidays having
|