2011-11-06 10 views
13

Tôi đang gặp một vấn đề mà tôi nhận được một lỗi như thế này:SQLAlchemy StaleDataError về xóa các mục chèn qua ORM sqlalchemy.orm.exc.StaleDataError

"MyPyramidApplication Error"<class 'sqlalchemy.orm.exc.StaleDataError'>: DELETE statement on table 'page_view' expected to delete 6 row(s); Only 0 were matched. 

Vì vậy, tôi có một ý tưởng tốt những gì đang gây ra sự cố nhưng tôi không thể giải quyết được vấn đề.

Tôi có mô hình page_view, có một khóa ngoại trên page_iduser_id.

Đây là những gì mô hình trông giống như:

page_view_table = sa.Table(
    'page_view', 
    metadata, 
    sa.Column('id', sa.Integer, primary_key=True), 
    sa.Column('page_id', sa.Integer, sa.ForeignKey('guide.id')), 
    sa.Column('user_id', sa.Integer, sa.ForeignKey('user.id')), 
    sa.Column('last_view', sa.DateTime, nullable=False), 
    sa.UniqueConstraint('user_id', 'page_id'), 
    mysql_engine='InnoDB', 
    mysql_charset='utf8mb4' 
) 

Đây là những gì các mối quan hệ giống như

orm.mapper(Page, page_table, 
    properties = { 
     'users_viewed': sa.orm.relation(
      User, 
      secondary=page_view_table, 
      backref='page'), 
    } 
) 

Tôi thêm một số mặt hàng cơ sở dữ liệu của tôi sử dụng một tuyên bố chèn, một cái gì đó tương tự như sau:

ins = model.page_view_table.insert() 
sql = str(ins) 
sql += ' ON DUPLICATE KEY UPDATE last_view = :last_view' 
session = model.Session() 
session.execute(sql, page_views) 
mark_changed(session) 

Theo như tôi có thể biết từ nhật ký, giao dịch được thực hiện đúng và tôi thấy các mục trong DB.

Tuy nhiên, khi tôi cố gắng xóa mục trang bằng cách sử dụng ORM, tôi nhận được ngoại lệ StaleDataError. Nhìn vào nhật ký, tôi thấy ORM đưa ra một tuyên bố xóa nhưng sau đó quay lại do lỗi.

Tôi đã thử nghiệm với session.expire_all() cũng như session.expunge_all() ngay sau câu lệnh chèn nhưng chúng không hữu ích và tôi vẫn là lỗi.

Đây là những gì tôi thấy trong nhật ký SQLAlchemy.

2011-11-05 18:06:08,031 INFO [sqlalchemy.engine.base.Engine][worker 3] DELETE FROM page_view WHERE page_view.page_id = %s AND page_view.user_id = %s 
2011-11-05 18:06:08,031 INFO [sqlalchemy.engine.base.Engine][worker 3] (13818L, 259L) 
2011-11-05 18:06:08,032 INFO [sqlalchemy.engine.base.Engine][worker 3] DELETE FROM page_view WHERE page_view.page_id = %s AND page_view.user_id = %s 
2011-11-05 18:06:08,033 INFO [sqlalchemy.engine.base.Engine][worker 3] (13818L, 259L) 
2011-11-05 18:06:08,033 INFO [sqlalchemy.engine.base.Engine][worker 3] ROLLBACK 

Tôi nghĩ câu lệnh xóa kép là nghi ngờ, có thể trỏ đến mối quan hệ ORM bị định cấu hình sai nhưng tôi không nghĩ vậy.

Trả lời

3

Tôi đoán tôi có thể đưa ra gợi ý gợi ý về sự cố này. Phiên bản ngắn gọn là: "Bạn có thể sẽ phải sửa đổi dữ liệu trong Cơ sở dữ liệu theo cách thủ công để giải quyết vấn đề".

Phiên bản dài hơn: Tôi gặp sự cố tương tự với SQLite. Tôi đã có bảng sau được ánh xạ:

ingredients = Table('ingredients', metadata, 
    Column('recipe_title', Unicode, ForeignKey('recipes.title'), primary_key=True), 
    Column('product_title', Unicode, ForeignKey('products.title'), primary_key=True), 
    Column('amount', Integer, nullable=False), 
    Column('unit_title', Unicode, ForeignKey('units.title'))) 

xem khóa tổng hợp chính? Tôi bằng cách nào đó quản lý để chèn hai hàng với cùng một recipe_title/product_title cặp. Tôi đã ngạc nhiên khi thấy rằng không có một ràng buộc nào ở phía bên của SQLite cho bảng này (không có khóa chính, không có khóa fereign - nó chỉ là một bảng vani đơn giản), nhưng tốt - đó là cách sqlalchemy đi, chứ không phải của tôi kinh doanh.

Sau đó, khi tôi cố gắng xóa một đối tượng bị kéo dài liên quan đến hai hàng đó, sqlalchemy thấy rằng các ràng buộc của nó đã bị vi phạm và nó đã ném 'StaleDataError'. Cuối cùng tôi đã phải gỡ bỏ một hàng trùng lặp bằng tay từ bảng SQLite.

1

Mặc dù cột có thể được đánh dấu là primary_key, hãy đảm bảo điều này cũng được thực thi ở cấp cơ sở dữ liệu (ví dụ khi cơ sở dữ liệu được tạo bởi một số công cụ khác). Trong MySQL, điều này có nghĩa là đảm bảo chúng là PRIMARY KEY và không chỉ KEY.

Trong trường hợp của tôi có 2 cột được đánh dấu là primary_key (hỗn hợp) nhưng có nhiều hàng chứa cùng một (được cho là) ​​duy nhất của id.

+0

Để cải thiện câu trả lời này, vui lòng viết lại --- chẳng hạn như "Mặc dù cột có thể được đánh dấu là primary_key cơ sở dữ liệu không thể thực thi chúng như vậy. Đảm bảo rằng chúng là CHÍNH THỨC và không KEY bằng cách thực hiện " Hoặc đây không phải là câu trả lời cho câu hỏi ban đầu, hãy xóa nó đi. –