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
> <[email protected] <mailto:[email protected]>> 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 [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/sqlalchemy?hl=en.