for child in childlist.deleted_items() + childlist.unchanged_items():
if child is None:
continue
- uowcommit.register_object(child, isdelete=True)
+ # if private child object, and is in the uow's "deleted" list,
+ # insure its in the list of items to be deleted
+ if child in uowcommit.uow.deleted:
+ uowcommit.register_object(child, isdelete=True)
elif self.post_update:
# post_update means we have to update our row to not reference the child object
# before we can DELETE the row
# head object is being deleted, and we manage its list of child objects
# the child objects have to have their foreign key to the parent set to NULL
if self.private and not self.post_update:
- # if we are privately managed, then all our objects should
- # have been marked as "todelete" already and no attribute adjustment is needed.
- # however, if they say objectstore.commit(x), i.e. on an individual object,
- # then this extra step is more important.
for obj in deplist:
childlist = getlist(obj, False)
for child in childlist.deleted_items() + childlist.unchanged_items():
if child is None:
continue
- uowcommit.register_object(child, isdelete=True)
+ # if private child object, and is in the uow's "deleted" list,
+ # insure its in the list of items to be deleted
+ if child in uowcommit.uow.deleted:
+ uowcommit.register_object(child, isdelete=True)
else:
for obj in deplist:
childlist = getlist(obj, False)
for child in childlist.deleted_items():
if not self.private:
self._synchronize(obj, child, None, True)
- if self.direction == PropertyLoader.ONETOMANY:
- # for a cyclical task, this registration is handled by the objectstore
uowcommit.register_object(child, isdelete=self.private)
def execute(self, instance, row, identitykey, imap, isnew):
def list_value_changed(self, obj, key, item, listval, isdelete):
sess = get_session(obj)
if not isdelete and sess.deleted.contains(item):
- raise InvalidRequestError("re-inserting a deleted value into a list")
+ #raise InvalidRequestError("re-inserting a deleted value into a list")
+ del sess.deleted[item]
sess.modified_lists.append(self)
if self.deleteremoved and isdelete:
sess.register_deleted(item)
e.assigned = datetime.date.today()
e.data = 'some more data'
objectstore.commit()
+
+class PrivateAttrTest(AssertMixin):
+ """tests various things to do with private=True mappers"""
+ def setUpAll(self):
+ global a_table, b_table
+ a_table = Table('a',testbase.db,
+ Column('a_id', Integer, Sequence('next_a_id'), primary_key=True),
+ Column('data', String(10)),
+ ).create()
+
+ b_table = Table('b',testbase.db,
+ Column('b_id',Integer,Sequence('next_b_id'),primary_key=True),
+ Column('a_id',Integer,ForeignKey('a.a_id')),
+ Column('data',String(10))).create()
+ def tearDownAll(self):
+ b_table.drop()
+ a_table.drop()
+ def setUp(self):
+ objectstore.clear()
+ clear_mappers()
+
+ def testsinglecommit(self):
+ """tests that a commit of a single object deletes private relationships"""
+ class A(object):pass
+ class B(object):pass
+
+ assign_mapper(B,b_table)
+ assign_mapper(A,a_table,properties= {'bs' : relation
+ (B.mapper,private=True)})
+
+ # create some objects
+ a = A(data='a1')
+ a.bs = []
+
+ # add a 'B' instance
+ b1 = B(data='1111')
+ a.bs.append(b1)
+
+ # add another one
+ b2 = B(data='2222')
+ a.bs.append(b2)
+
+ # inserts both A and Bs
+ objectstore.commit(a)
+
+ objectstore.delete(a)
+ objectstore.commit(a)
+
+ assert b_table.count().scalar() == 0
+
+ def testswitchparent(self):
+ """tests that you can switch the parent of an object in a backref scenario"""
+ class A(object):pass
+ class B(object):pass
+
+ assign_mapper(B,b_table)
+ assign_mapper(A,a_table,properties= {
+ 'bs' : relation (B.mapper,private=True, backref='a')}
+ )
+ a1 = A(data='testa1')
+ a2 = A(data='testa2')
+ b = B(data='testb')
+ b.a = a1
+ objectstore.commit()
+ objectstore.clear()
+ sess = objectstore.get_session()
+ a1 = A.mapper.get(a1.a_id)
+ a2 = A.mapper.get(a2.a_id)
+ assert a1.bs[0].a is a1
+ b = a1.bs[0]
+ b.a = a2
+ assert b not in sess.deleted
+ objectstore.commit()
class DefaultTest(AssertMixin):
"""tests that when saving objects whose table contains DefaultGenerators, either python-side, preexec or database-side,