5

I am trying to delete an order from my database while deleting all ordereditems that relate to it.

with contextlib.closing(DBSession()) as session:
    try:
        returnedOrder = session.query(ORDER).filter_by(ORDERSID=orderID).first()
        session.delete(returnedOrder)
        session.commit()
    except exc.SQLAlchemyError, error:
        session.rollback()
        raise_database_error(error)
    else:
        return '1'

Here are the related classes (some items have been removed):

class ORDER(Base):
    __tablename__ = 'ORDERS'

    ORDERSID = Column(Integer, primary_key=True)
    ORDERSCOST = Column(Numeric(19, 4), nullable=False)

    ORDEREDITEM = relationship("ORDEREDITEM")  


class ORDEREDITEM(Base):
    __tablename__ = 'ORDEREDITEMS'
    __table_args__ = (
        Index('AK_ORDERSID_ITEMID', 'ORDERSID', 'ITEMSID', unique=True),
    )

    ORDEREDITEMSID = Column(Integer, primary_key=True)
    ITEMSID = Column(ForeignKey(u'ITEMS.ITEMSID'), nullable=False, index=True)
    ORDERSID = Column(ForeignKey(u'ORDERS.ORDERSID', ondelete=u'CASCADE'), nullable=False)
    ORDEREDITEMSQUANTITY = Column(Integer, nullable=False)

    ORDER = relationship(u'ORDER')

The SQL file:

create table ORDERS
(
 ORDERSID             int not null auto_increment,     
 ORDERSCOST           decimal(19,4) not null,
 primary key (ORDERSID)
);

create table ORDEREDITEMS
(
 ORDEREDITEMSID       int not null auto_increment,
 ORDERSID             int not null,
 ITEMSID              int not null,
 ORDEREDITEMSQUANTITY int not null,
 primary key (ORDEREDITEMSID),
 unique key AK_ORDERSID_ITEMID (ORDERSID, ITEMSID)
);

alter table ORDEREDITEMS add constraint FK_ORDER_ORDEREDITEM foreign key (ORDERSID)
  references ORDERS (ORDERSID) on delete CASCADE on update restrict;

When I run this, I get the error:

 (IntegrityError) (1452, 'Cannot add or update a child row: a foreign key constraint fails (`my_database`.`ordereditems`,

 CONSTRAINT `FK_ORDER_ORDEREDITEM` FOREIGN KEY (`ORDERSID`) REFERENCES `ORDERS` (`ORDERSID`) ON DELETE CASCADE)') 

'UPDATE `ORDEREDITEMS` SET `ORDERSID`=%s WHERE `ORDEREDITEMS`.`ORDEREDITEMSID` = %s' (None, 3L)

When I perform the same operation directly on phpMyAdmin, it works as expected.

Francisco
  • 10,918
  • 6
  • 34
  • 45

2 Answers2

6

A fully working example is usually most helpful, but I was able to filling in the missing parts from your example, and reproduce your exact problem-- the UPDATE statement that is attempted when trying to commit after delete. (Fully working code here, all pure python, no SQL statements.)

This question has been asked before many times, and I found the answer in this SO question.

The fix is simply to change the ORDEREDITEM relationship from

ORDEREDITEM = relationship("ORDEREDITEM")

to

ORDEREDITEM = relationship("ORDEREDITEM", cascade="all,delete")

See the sqlalchemy docs here.

Community
  • 1
  • 1
snapshoe
  • 13,454
  • 1
  • 24
  • 28
  • In addition since the DB foreign key constraint has ON DELETE CASCADE, the ORM relationship could leave deleting to the DB by passing `passive_deletes=True` instead of `cascade="..., delete"`: http://docs.sqlalchemy.org/en/latest/orm/collections.html#passive-deletes – Ilja Everilä Mar 06 '18 at 11:19
0

Foreign key relationships involve a parent table that holds the central data values, and a child table with identical values pointing back to its parent. The FOREIGN KEY clause is specified in the child table.

It will reject any INSERT or UPDATE operation that attempts to create a foreign key value in a child table if there is no a matching candidate key value in the parent table.

SO Answers for Foreign Key Constraint OR Integrity Error

Update

    create table ORDERS
    (
     ORDERSID             int not null auto_increment,     
     ORDERSCOST           decimal(19,4) not null,
     primary key (ORDERSID)
    );

    create table ORDEREDITEMS
    (
     ORDEREDITEMSID       int not null auto_increment,
     ORDERSID             int not null,
     ITEMSID              int not null,
     ORDEREDITEMSQUANTITY int not null,
     primary key (ORDEREDITEMSID),
     unique key AK_ORDERSID_ITEMID (ORDERSID, ITEMSID)
    );

    alter table ORDEREDITEMS add constraint FK_ORDER_ORDEREDITEM foreign key (ORDERSID)
      references ORDERS (ORDERSID) on delete CASCADE on update restrict;
      
    INSERT into ORDERS values(1,20.00);
    INSERT into ORDEREDITEMS values(1,1,1,2);

Now when you run above command in MySql your data is inserted successfully in Orders and ORDEREDITEMS DEMO1

So when does this error generates

(IntegrityError) (1452, 'Cannot add or update a child row: a foreign key constraint fails

It's generated when your child (ORDEREDITEM) has invalid key of Parent(i.e child contains invalid foreign key which is either deleted or does not exist from your Parent table)

If i try to do this

    INSERT into ORDEREDITEMS values(1,1,1,2);
    INSERT into ORDERS values(1,20.00);

I get error as OP got just by changing order of Insertion
even while deleting you can face this error

    INSERT into ORDERS values(1,20.00);

    DELETE FROM ORDERS
    WHERE ORDERSID=1;

    INSERT into ORDEREDITEMS values(1,1,1,2);
Community
  • 1
  • 1
CY5
  • 1,551
  • 17
  • 23
  • Sorry I don't quite understand your answer. I'm trying to `Delete` a row. In my `OrderedItems` table, there are rows with an `orderID` that corresponds to the `Order` table. –  Apr 04 '15 at 07:58
  • Essentially, try to delete the `ORDEREDITEM` rows that belong to the `ORDER` before you delete the `ORDER`. – Stefan Schmidt Apr 09 '15 at 09:31
  • Thanks @StefanSchmidt. This is what I was initially doing but thought using `cascade` would be a simpler solution. –  Apr 09 '15 at 10:51
  • Doesn't you error relate to this line `'UPDATE `ORDEREDITEMS` SET `ORDERSID`=%s WHERE `ORDEREDITEMS`.`ORDEREDITEMSID` = %s' (None, 3L)` which is an update not a delete? The null value here violates your constraint. – gonkan Apr 09 '15 at 11:08
  • Thanks @gonkan. Yes.. I'm not sure why it is trying to `update` the entry and not simply `delete` it. I thought it would find all `ordereditems` with a particular `ordersID` and `delete` them. Finally it would delete the `ORDER` with that `id`. –  Apr 09 '15 at 12:38
  • @Giri, that would be my expectation as well. I've used cascade from SQLAlchemy before (http://docs.sqlalchemy.org/en/latest/orm/cascades.html#cascade-delete-orphan) without issue. – gonkan Apr 09 '15 at 13:33