[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 |