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.


Reply via email to