From: Mike Bayer Date: Thu, 30 Nov 2006 00:08:46 +0000 (+0000) Subject: - improved support for disabling save-update cascade via cascade="none" etc. X-Git-Tag: rel_0_3_2~30 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=117d6eb521e59d797cae8be279c70b3650e0ea4a;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - improved support for disabling save-update cascade via cascade="none" etc. --- diff --git a/CHANGES b/CHANGES index df487cf267..f5ea33a5d3 100644 --- a/CHANGES +++ b/CHANGES @@ -9,7 +9,7 @@ an instance is detected to be already in the session. - sending a selectable to an IN no longer creates a "union" out of multiple selects; only one selectable to an IN is allowed now (make a union yourself if union is needed; explicit better than implicit, dont guess, etc.) - +- improved support for disabling save-update cascade via cascade="none" etc. 0.3.1 - Engine/Pool: - some new Pool utility classes, updated docs diff --git a/lib/sqlalchemy/orm/unitofwork.py b/lib/sqlalchemy/orm/unitofwork.py index a6f789e51a..4ecf8b4a04 100644 --- a/lib/sqlalchemy/orm/unitofwork.py +++ b/lib/sqlalchemy/orm/unitofwork.py @@ -101,7 +101,14 @@ class UnitOfWork(object): if (hasattr(obj, '_instance_key') and not self.identity_map.has_key(obj._instance_key)) or \ (not hasattr(obj, '_instance_key') and obj not in self.new): raise InvalidRequestError("Instance '%s' is not attached or pending within this session" % repr(obj)) - + + def _is_valid(self, obj): + if (hasattr(obj, '_instance_key') and not self.identity_map.has_key(obj._instance_key)) or \ + (not hasattr(obj, '_instance_key') and obj not in self.new): + return False + else: + return True + def register_attribute(self, class_, key, uselist, **kwargs): attribute_manager.register_attribute(class_, key, uselist, **kwargs) @@ -219,9 +226,9 @@ class UOWTransaction(object): registration is entered for the object.""" #print "REGISTER", repr(obj), repr(getattr(obj, '_instance_key', None)), str(isdelete), str(listonly) - # things can get really confusing if theres duplicate instances floating around, - # so make sure everything is OK - self.uow._validate_obj(obj) + # if object is not in the overall session, do nothing + if not self.uow._is_valid(obj): + return mapper = object_mapper(obj) self.mappers.add(mapper) diff --git a/test/orm/session.py b/test/orm/session.py index 3f8adc3e9c..5cb7009bb5 100644 --- a/test/orm/session.py +++ b/test/orm/session.py @@ -12,7 +12,6 @@ from sqlalchemy import * class SessionTest(AssertMixin): def setUpAll(self): tables.create() - tables.data() def tearDownAll(self): tables.drop() def tearDown(self): @@ -93,6 +92,42 @@ class SessionTest(AssertMixin): assert user in s assert user not in s.dirty + def test_no_save_cascade(self): + mapper(Address, addresses) + mapper(User, users, properties=dict( + addresses=relation(Address, cascade="none", backref="user") + )) + s = create_session() + u = User() + s.save(u) + a = Address() + u.addresses.append(a) + assert u in s + assert a not in s + s.flush() + s.clear() + assert s.query(User).selectone().user_id == u.user_id + assert s.query(Address).selectfirst() is None + + clear_mappers() + + tables.delete() + mapper(Address, addresses) + mapper(User, users, properties=dict( + addresses=relation(Address, cascade="all", backref=backref("user", cascade="none")) + )) + + s = create_session() + u = User() + a = Address() + a.user = u + s.save(a) + assert u not in s + assert a in s + s.flush() + s.clear() + assert s.query(Address).selectone().address_id == a.address_id + assert s.query(User).selectfirst() is None class OrphanDeletionTest(AssertMixin):