Sqlalchemy 删除子查询

57

我尝试使用过滤查询删除一些子行,但没有结果:

sl = DBSession.query(Puesto.id).filter(Puesto.locales_id == id).subquery()
DBSession.query(Servicio).filter(Servicio.puestos_id.in_(sl)).delete()

我得到了一个错误:InvalidRequestError: Could not evaluate current criteria in Python. Specify 'fetch' or False for the synchronize_session parameter.

完整的堆栈跟踪:

Traceback (most recent call last):
  File "/usr/src/tg2env/ceaf/ceaf/controllers/root.py", line 1673, in delete_local
    DBSession.query(Servicio).filter(Servicio.puestos_id.in_(sl)).delete()
  File "/usr/src/tg2env/lib/python2.4/site-packages/SQLAlchemy-0.6.6-py2.4.egg/sqlalchemy/orm/query.py", line 2126, in delete
    raise sa_exc.InvalidRequestError(
InvalidRequestError: Could not evaluate current criteria in Python.  Specify 'fetch' or False for the synchronize_session parameter.

我找不到问题出在哪里了...

有什么想法吗?

谢谢

1个回答

100

在查看引发异常的代码后,我建议尝试以下操作:

sl = DBSession.query(Puesto.id).filter(Puesto.locales_id == id).subquery()
DBSession.query(Servicio).filter(Servicio.puestos_id.in_(sl)) \
.delete(synchronize_session='fetch')

请查看delete方法的文档了解其含义。如果传递fetch参数,将基本上运行两次查询,一次作为选择操作,一次作为删除操作。

如果不希望运行两个查询,请传递synchronize_session=False,然后在删除操作之后立即调用session.expire_all(),以避免在MetaData存储中出现不一致的状态


1
第一种方法很好用。为什么使用synchronize_session='evaluate'时不起作用? - LooPer
3
由于删除操作使用了带有子查询的 in_,因此 MetaData 需要执行一个 select 查询来确定需要过期的内存对象。传递此选项可以让它获得执行该查询的权限。无条件地执行此操作可能会在某些情况下导致性能不佳。 - wberry
4
这份文件还提到,如果我们立即提交(commit)操作,就不需要调用session.expire_all()方法,前提是autocommit参数设置为False。 - Shafiul
2
@Shafiul 你确定吗?我理解的是,如果这个删除操作发生在提交之后而不是之前,那么你就不需要调用 expire_all。如果在同一数据库事务中在此删除之前进行了其他操作,则会话中可能存在没有对应表中行的对象! - wberry
DBSessionsession究竟是什么? - Hosein Aqajani
session 对象本质上是累积映射对象所做的更改,并从中计算在提交时需要执行哪些查询。Session 对象是短暂的,由一个工厂对象创建,按惯例称为 Session(大写 S)。Session 对象的寿命应该很短,范围应该限制在单个事务中,并且不应该共享。 - wberry

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接