Cascading with "delete-orphan" will insert new children, before deleting removed children, causing unique constraint violations

Issue #2765 resolved
Former user created an issue

This issue occurs under the following circumstances: * When a relationship has the cascade property set to "all, delete-orphan", * There is a UniqueConstraint set on the child model * Simultaneously deleting and creating new child objects, through the backref on the parent, that have common values in the unique fields

I believe this is a bug, and that it can be fixed by first deleting the removed children, followed by insertion of new children.

The following example recreates the issue on SQLAlchemy 0.8.1.

from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String, Float, UniqueConstraint, ForeignKey
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship, backref
from sqlalchemy.orm.dependency import OneToManyDP, attributes

Base = declarative_base()

class ParentEntity(Base):
    __tablename__ = 'parent'

    id = Column(Integer, primary_key=True)
    name = Column(String)

class ChildEntity(Base):
    __tablename__ = 'child'

    __table_args__ = (UniqueConstraint('parent_id', 'z', name='child_uk'),)

    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey('parent.id'), nullable=False)
    z = Column(Float)

    parent = relationship("ParentEntity",
                          backref=backref("children",
                                          cascade="all, delete-orphan"))

engine = create_engine('sqlite://', echo=True)
Session = sessionmaker(bind=engine)

sess = Session()
Base.metadata.create_all(engine)

p = ParentEntity(name='Datum')
p.children = [ChildEntity(z=3.5), ChildEntity(z=5.5)](ChildEntity(z=2.5),)
sess.add(p)
sess.commit()

# Remove all existing children and create new, one of which is identical to a previously existing child
p.children = [ChildEntity(z=5.5)](ChildEntity(z=4.0),)
sess.commit()

Running this example produces the following error:

sqlalchemy.exc.IntegrityError: (IntegrityError) columns parent_id, z are not unique u'INSERT INTO child (parent_id, z) VALUES (?, ?)' (1, 5.5)

Comments (5)

  1. Mike Bayer repo owner

    a new proof of concept illustrating the basic idea for UOW changes has been attached to #2501. It takes stock of the basic mechanics we'd have to use in order to achieve this.

  2. Mike Bayer repo owner

    yeah and a patch. It uses a new setting, which if not used means there's no change to current behavior. Will see if it can go in for 0.9.

  3. Former user Account Deleted

    Sorry about the duplicate report, I didn't find the other ticket by search. Thanks for looking into it, I see now that it is a more complicated issue.

  4. Log in to comment