删除通过 ORM 插入的项目时出现 SQLAlchemy StaleDataError 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.
所以,我很清楚导致问题的原因,但我一直无法解决它。
我有一个 page_view 模型,它在 page_id
和 user_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'),
}
)
我正在使用插入语句向数据库添加一些项目,类似于以下内容:
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 发出了一条删除语句,但随后由于错误而回滚。
我尝试在插入语句之后尝试使用 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
我认为双重删除语句是可疑的,可能指向错误配置的 ORM 关系,但我认为情况并非如此。
I'm having an issue where I get a an error such as this one:
"MyPyramidApplication Error"<class 'sqlalchemy.orm.exc.StaleDataError'>: DELETE statement on table 'page_view' expected to delete 6 row(s); Only 0 were matched.
So, I have a good idea what is causing the issue but I have been unable to solve it.
I have a page_view model, that has a foreign key on page_id
and a user_id
.
Here's what the model looks like:
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'
)
Here's what the relations look like
orm.mapper(Page, page_table,
properties = {
'users_viewed': sa.orm.relation(
User,
secondary=page_view_table,
backref='page'),
}
)
I am adding some items to my database using an insert statement, something similar to this:
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)
As far as I can tell from the logs, the transactions gets committed properly and I see the items in the DB.
However, when I try to delete the page item using the ORM, I get the StaleDataError exception. Looking at the logs, I see the ORM issuing a delete statement but then rolling back due to the error.
I have tried experimenting with session.expire_all()
as well as session.expunge_all()
right after the insert statement but they weren't very helpful and I still the error.
Here's what I see in the SQLAlchemy logs.
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
I thought the double delete statement was a suspect, maybe pointing to a misconfigured ORM relation but I don't think that's the case.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我想我可以对这个问题给出一个提示。简短的版本是:“您可能必须手动修改数据库中的数据才能解决问题”。
较长的版本:我在 SQLite 上也遇到了类似的问题。我映射了下表:
看到复合主键了吗?我以某种方式设法插入具有相同的recipe_title/product_title对的两行。我惊讶地发现这个表的 SQLite 方面没有任何约束(没有主键,没有外键 - 它只是一个普通的普通表),但是好吧 - 这就是 sqlalchemy 的方式,而不是我的方式商业。
然后,当我尝试删除涉及这两行的持久对象时,sqlalchemy 发现它的约束被违反,并抛出“StaleDataError”。最后,我只需从 SQLite 表中手动删除一行重复的行。
I guess I can give a hint on this problem. The short version is: "You will probably have to modify data in the Database manually to solve the issue".
The longer version: I had a similar issue with SQLite. I had the following table mapped:
see that composite primary key? I somehow managed to insert two rows with the same recipe_title/product_title pair. I was surprized to find out that there were not a single constraint on the side of SQLite for this table (no primary key, no fereign key - it was just a plain vanilla table), but well - thats the way sqlalchemy goes, not my business.
Then when I tried to delete a persited object involving those two rows, sqlalchemy saw that it's constraints were violated and it threw the 'StaleDataError'. Finally I just had to remove one duplicatinng row manually from SQLite table.
尽管列可以标记为
primary_key
,但请确保这也在数据库级别强制执行(例如,当数据库是由某些不同的工具创建时)。在 MySQL 中,这意味着确保它们是PRIMARY KEY
,而不仅仅是KEY
。在我的例子中,有 2 列标记为
primary_key
(复合),但有多行包含相同的(据称)唯一id
。Although columns can be marked as
primary_key
, make sure this is enforced on the database level as well (for example when the database was created by some different tool). In MySQL this means ensuring they arePRIMARY KEY
and not onlyKEY
.In my case there were 2 columns marked as
primary_key
(composite) but there were multiple rows containing the same (supposedly) uniqueid
's.