On Mar 25, 2006, at 12:17 AM, Tiago Cogumbreiro wrote:
bi-directional relationships do this: del child1.childs[child3] assert child3.father is None objectstore.delete() doesnt do anything to object relationships, it instructs the unit of work that a SQL DELETE statement will be issued when it is committed. all of the problems you are having with this program are because you are expecting the above relationship to be automatically modified by marking "child1" as deleted with the unit of work, which it doesnt. the unit of work expects that you will do everything to your objects manually. Once all of your objects are just the way you want them, you then can additionally mark objects that you want deleted from the database as deleted, and then calling objectstore.commit() will persist all those changes and deletions you have indicated to the database. there was a comment some weeks earlier that objectstore.delete(obj) should remove "obj" from the parent list that its attached to. to which I replied, what if "obj" is attached to 308 different parent lists ? then SA would have to maintain a lookup table of every object every other object is attached to, which seems like a huge amount of cruft, certain to introduce a lot more bugs than it "fixes", just to be a minor convenience for an application that doesnt want to worry about how its own domain objects are structured. its all way out of the scope of SA, which just wants to generate SQL statements, load objects, and save them. it doesnt want to be involved with how you manipulate them. the backref thing is the *only* exception to this, as it was requested by users, and i almost regret it for all the confusion it creates.
remove the "clear()". refresh()/expire() require that the object youre dealing with is still present in the unit of work. issuing a clear() replaces the existing unit of work with a new one, so it essentially removes everything.
every mapped object that you deal with is tracked by a unit of work object, which is accessible via objectstore.get_session(). when you clear() the current unit of work, it creates a new session. objects that are lying around from the previous session will not interact with unit of work operations very well, since they are no longer present in the unit of work. those objects are completely gone from the UOW. they will not have their fields refreshed, they wont be marked as dirty, they wont be saved, or deleted, or anything, even if you pass them into various unit of work functions the results are undefined. if you clear your unit of work its expected that you are starting totally clean.
the program is based on the example that comes with the SA distribution. the version that comes with the distribution does not have a clear() inside it, so I found it strange that you thought clear() was required. if you comment out the clear(), the subsequent tests fail because you are selecting objects that already exist in the current unit of work session. the unit of work maintains an "identity map" of objects, such that only one instance of an object corresponding to a particular database identity can exist within the session at one time. so new_child3 is the same object as child3 (*provided you dont clear the unit of work in between*), just do an assertion on that and youll see.
if you write a web application, say a mod python handler, you write a function called handle(r), where 'r' is a mod_python request object. Suppose you load three or four objects from the database within your handle(). then you change some around, save them, etc., then send a response to the user. then three hours later, another user comes in (its a very unpopular site), calls the same handle(r) function. you go to select objects from the database, some of which are the same objects used in the last request, some of which are not. the objects that you loaded in the previous request *will be the same*, since they are still present in the unit of work from last time, and wont get refreshed, even when you query the databse for them. the second user now gets data of which some of it is three hours old, some of it fresh. thats why you clear the objectstore.
if you want deletes to cascade, use the "private=True" flag: assign_mapper(Tree, table, properties={ 'childs':relation(Tree, foreignkey=table.c.father_id, primaryjoin=table.c.father_id==table.c.id, backref=backref('father', uselist=False, foreignkey=table.c.id), private=True) }) child1.delete() objectstore.commit() # deletes child1 and child3 new_child3 = Tree.get_by(name="child3") assert new_child3 is None however, remember when I say "deletes", I am only talking about SQL. your old "child3" and "child1" objects are still present in your program, just not in the database. its expected that you will dereference those objects yourself.
yah, thats exactly what it does, not like theres an entire section in the docs on that or anything..... http://www.sqlalchemy.org/docs/unitofwork.myt#unitofwork_identity ;) |
- [Sqlalchemy-users] Problem understanding deletes Tiago Cogumbreiro
- Re: [Sqlalchemy-users] Problem understanding delete... Michael Bayer
- Re: [Sqlalchemy-users] Problem understanding de... Tiago Cogumbreiro
- Re: [Sqlalchemy-users] Problem understandin... Michael Bayer
- Re: [Sqlalchemy-users] Problem understa... Tiago Cogumbreiro
- Re: [Sqlalchemy-users] Problem und... Michael Bayer