On Thu, Apr 3, 2014 at 4:44 PM, Joril <jor...@gmail.com> wrote: > Hi everyone! > I have a client-server application where sometimes I need to modify a > cascaded member of a one-to-many relation directly, that is by saving itself > instead of its parent. This works, but if later the user *does* save the > parent, I get a "A conflicting state is already present in the identity map" > error, and I don't know if I'm simply doing something I'm not supposed to :) > > I narrowed down the issue to this example: > > > from sqlalchemy import Column, String, Integer, Table, ForeignKey > from sqlalchemy.engine import create_engine > from sqlalchemy.orm import sessionmaker, relationship > from sqlalchemy.ext.declarative import declarative_base > > Base = declarative_base() > > class Child(Base): > __tablename__ = "children" > > id = Column(Integer, primary_key=True) > parent_id = Column(Integer, ForeignKey("parents.id")) > > class Parent(Base): > __tablename__ = "parents" > > id = Column(Integer, primary_key=True) > children = relationship(Child, cascade="save-update", uselist=True) > > en = create_engine("sqlite:///:memory:", echo=True) > Base.metadata.create_all(en) > maker = sessionmaker(en) > session = maker(autocommit=True) > > # Save a parent with a child > par = Parent() > par.children = [ Child() ] > session.add(par) > session.flush() > > child_id = par.children[0].id # For later > > # Clean the session (simulate another client-server session) > session.expunge_all() > > # Reload the children > q = session.query(Child) > q = q.filter(Child.id == child_id) > child_reloaded = q.first() > > # Reassign to the parent and save > par.children = [child_reloaded] > session.add(par) > > > I tested this on SQLalchemy 0.9.4: > > Traceback (most recent call last): > File "testsa.py", line 44, in <module> > session.add(par) > File "/home/joril/src/newprg/branches/sqla09/sqlalchemy/orm/session.py", > line 1478, in add > self._save_or_update_state(state) > File "/home/joril/src/newprg/branches/sqla09/sqlalchemy/orm/session.py", > line 1497, in _save_or_update_state > self._save_or_update_impl(st_) > File "/home/joril/src/newprg/branches/sqla09/sqlalchemy/orm/session.py", > line 1746, in _save_or_update_impl > self._update_impl(state) > File "/home/joril/src/newprg/branches/sqla09/sqlalchemy/orm/session.py", > line 1739, in _update_impl > self.identity_map.add(state) > File "/home/joril/src/newprg/branches/sqla09/sqlalchemy/orm/identity.py", > line 119, in add > % (key, )) > AssertionError: A conflicting state is already present in the identity map > for key (<class '__main__.Child'>, (1,)) > > Is this supposed to happen? > > Many thanks! >
I'm not sure if this is the reason for your error, but I don't think I'd expect your example to work because you are attaching the freshly loaded child instance to a parent which is no longer associated with a session. What happens in your test if you reload the parent instance first? Simon -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at http://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.