Dave Paola wrote: > Indeed, I do have TaskTags mapped to it's own class. However, I never > explicitly delete any TaskTag object, only create them. > > In any case, what would the preferred way to add a new tag to a task > (a new entry in the association table)? I was using the ORM to just > create a new instance of TaskTag (the mapped class). If having the > association table mapped to its own class becomes problematic, what's > the convention for accomplishing this? > > Thanks for your feedback :-) >
(I'm about 80% sure this paragraph is correct, so take it with a grain of salt). I'm guessing you also have a relation from Task to TaskTags (e.g. Task.task_tags). By default, many-to-many relations will cascade the delete to the the secondary table (so the Task.tags relation cascades DELETEs to tasktags_table), and one-to-many relations will set foreign key columns to NULL on the related table (so the Task.task_tags relation cascades UPDATEs to tasktags_table). Add this all up and SQLAlchemy will try to UPDATE a deleted row or DELETE an updated row, depending on which cascade happens first. A similar situation occurs if the Task.task_tags relation has cascade="delete" set (SQLAlchemy would try to DELETE a deleted row). Usually a table like tasktags_table has no columns except for foreign keys to the related tables (e.g. task_id and tag_id columns). If this is the case for your tasktags_table table, you probably don't want to map it at all: just use it as a secondary table in the relation. Otherwise, I would recommend the association_proxy method over the viewonly=True method, because the viewonly=True method leaves a lot of room for things to get out of sync until you commit or expire the session. To use the association_proxy, try this: from sqlalchemy.ext.associationproxy import association_proxy mapper(Task, tasks_table, properties = { # Assumes you have a TaskTag.tag relation. 'tags' : association_proxy( 'task_tags', 'tag', creator=lambda tag: TaskTag(tag=tag)), 'task_tags': relation(TaskTag, lazy=False) }) You only need the creator argument if you want to create TaskTag objects implicitly, e.g. my_task.tags.append(my_tag). I'm also guessing your TaskTag constructor accepts a "tag" keyword parameter. Hope it helps, -Conor > > On Wed, Dec 2, 2009 at 4:58 PM, Michael Bayer > <mike...@zzzcomputing.com <mailto:mike...@zzzcomputing.com>> wrote: > > > On Dec 2, 2009, at 5:46 PM, Dave Paola wrote: > >> I'm getting this: ConcurrentModificationError: updated rowcount 0 >> does not match number of objects updated 1 when I try to commit a >> simple deletion. I'm using Sqlite locally but the error also >> occurs on a Postgres database in a live environment with only ONE >> user connected. >> >> I saw this post from Nov. >> 11th: >> http://groups.google.com/group/sqlalchemy/browse_thread/thread/e7175c7351963128 >> but because I'm not doing any copying (just deletion), it didn't >> seem to provide anything useful. Both session.dirty and >> session.new are empty. >> >> I have a Task class mapped to an association table called TaskTag >> that has a task_id and tag_id. I'm literally doing a >> session.delete(task) followed by a session.commit() and >> session.close(). Here's my mapper: >> >> mapper(Task, tasks_table, properties = { >> 'tags' : relation(Tag, secondary=tasktags_table, >> lazy = False) >> }) >> >> I suspect this has something to do with the many-to-many >> relationship, but for the life of me I cannot figure out what's >> going on. Thanks in advance. > > this can happen if you have tasktags_table explicitly mapped > elsewhere. the mapper for tasktags_table will issue a DELETE, > and then if Task.tags is also modified in some way that affects > the same row, the DELETE issued corresponding to the relation() > will not find its row. In that case the "Concurrent" name is > referring to two different configurations within a single flush > conflicting with each other. If this is your issue, strategies to > address include placing viewonly=True on the relation() or using > the association proxy pattern (you can even use both if you want > to pick and choose how the SQL to load records is emitted). > >> P.S. I use SqlAlchemy so often, I love the framework. Thanks to >> everyone for your hard work, it's greatly appreciated :-) > > The compliments are appreciated ! > -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalch...@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.