删除通过ORM SQLAlchemy.ORM.exc.StaleDataE插入的项时发生SQLAlchemy StaleDataError

2024-05-12 22:31:23 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个问题,我得到一个错误,比如这个:

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

所以,我很清楚是什么导致了这个问题,但我一直无法解决。

我有一个页面视图模型,它在page_iduser_id上有一个外键。

下面是模型的外观:

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'
)

这是他们的关系

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

我正在使用insert语句向数据库中添加一些项,类似于:

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)

从日志中可以看出,事务得到了正确的提交,并且我看到了数据库中的项。

但是,当我尝试使用ORM删除页面项时,会出现StaleDataError异常。查看日志,我看到ORM发出delete语句,但是由于错误而回滚。

我试过在insert语句之后使用session.expire_all()session.expunge_all()进行实验,但它们并不是很有帮助,我仍然出错。

这是我在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

我认为double delete语句是一个嫌疑犯,可能指向一个配置错误的ORM关系,但我不认为是这样。


Tags: infoviewidbasesqlalchemysessionsapage
2条回答

尽管可以将列标记为primary_key,但也要确保在数据库级别强制执行(例如,当数据库由其他工具创建时)。在MySQL中,这意味着确保它们是PRIMARY KEY,而不仅仅是KEY

在我的例子中,有两列标记为primary_key(composite),但是有多行包含相同的(假定的)唯一的id

我想我可以给这个问题一个提示。简短的版本是:“您可能需要手动修改数据库中的数据来解决问题”。

更长的版本:我对SQLite也有类似的问题。我映射了下表:

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')))

看到复合主键了吗?不知怎么的,我设法插入了两行相同的菜谱标题/产品标题对。我很惊讶地发现,这个表的SQLite端没有一个约束(没有主键,没有fereign键-它只是一个普通的普通表),但是-这就是sqlalchemy的方式,而不是我的业务。

然后当我试图删除一个涉及这两行的persited对象时,sqlalchemy发现它的约束被违反了,并抛出了“StaleDataError”。最后,我不得不从SQLite表中手动删除一个复制行。

相关问题 更多 >