I'm writing a GUI app that uses SA sessions extensively to save/update/delete
graphs of persistent objects. The session usually does a pretty good job of
figuring out what SQL needs to be executed to persist the entire object graph
on session.flush(). However, I'm having problems with creating and then
deleting the same object (and its children) within a session. Here's a short
example that demonstrates the problem:
01 mapper(Address, addresses)
02 mapper(User, users, properties=dict(
03 addresses=relation(Address,
04 cascade="all,delete-orphan",
05 backref="user"
06 )
07 ))
08 s = create_session()
09
10 u = User()
11 s.save(u)
12
13 a = Address()
14 u.addresses.append(a)
15
16 # later before session is flushed
17 u.addresses.remove(a)
18
19 # and even later the user is deleted
20 s.delete(u)
21
22 s.flush() # finally persist pending changes
23 # this (erroneously) causes "a" to be persisted
23 # even though it was never saved in the session
This is a minimal example to demonstrate the problem. In actuality the end-user will be adding lots
of new Users and Addresses (fictional entities used for this example only) some of which will be
saved and others will be "deleted" before they ever get the chance to become persistent.
The problem I am having is a side affect of the fact that the new Address (a) is registered as
"new" in the session when it is appended to u.addresses (line 14), but it is not
unregistered when it is removed from u.addresses (line 17).
I think that's a bug. A test case is also attached.
~ Daniel
from testbase import AssertMixin
import testbase
import unittest, sys, datetime
import tables
from tables import *
db = testbase.db
from sqlalchemy import *
class SessionTest(AssertMixin):
def setUpAll(self):
db.echo = False
tables.create()
tables.data()
db.echo = testbase.echo
def tearDownAll(self):
db.echo = False
tables.drop()
db.echo = testbase.echo
def tearDown(self):
clear_mappers()
def setUp(self):
pass
def test_delete_new_object(self):
mapper(Address, addresses)
mapper(User, users, properties=dict(
addresses=relation(Address, cascade="all,delete-orphan",
backref="user")
))
s = create_session()
u = User()
s.save(u)
a = Address()
assert a not in s.new
u.addresses.append(a)
#assert a not in s.new # fails
u.addresses.remove(a)
#assert a not in s.new # fails
s.delete(u)
s.flush() # (erroneously) causes "a" to be persisted
assert u.user_id is None, "Error: user should not be persistent"
assert a.address_id is None, "Error: address should not be persistent"
"""
Suggested behavior:
instead of immediately registering objects that are added to a
collection
as "new", the registration should be deferred until the session is
flushed.
On session.flush() any object "u" with a non-persistent child "a" and a
cascading save rule will cause "a" to be persisted at that time.
"""
if __name__ == "__main__":
testbase.main()
-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
Sqlalchemy-users mailing list
Sqlalchemy-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sqlalchemy-users