【问题标题】:Deleting an object from an SQLAlchemy session before it's been persisted在持久化之前从 SQLAlchemy 会话中删除对象
【发布时间】:2011-11-29 05:53:52
【问题描述】:

我的应用程序允许用户创建和删除Site 对象。我已经使用session.add()session.delete() 实现了这一点。然后我有调用session.commit()session.rollback() 的“保存”和“重置”按钮。

如果我添加一个新的Site,然后保存/提交它,然后删除它,一切正常。但是,如果我在保存对象之前尝试从会话中删除它,则会收到“未持久化”错误。

代码:

self.newSite = Site('foo')
self.session.add(self.newSite)
print self.session.new
self.session.delete(self.newSite)

输出:

IdentitySet([<Site('foo')>])

Traceback (most recent call last):
  File "C:\Program Files\Eclipse\dropins\plugins\org.python.pydev.debug_2.2.1.2011071313\pysrc\pydevd_comm.py", line 744, in doIt
    result = pydevd_vars.evaluateExpression(self.thread_id, self.frame_id, self.expression, self.doExec)
  File "C:\Program Files\Eclipse\dropins\plugins\org.python.pydev.debug_2.2.1.2011071313\pysrc\pydevd_vars.py", line 375, in evaluateExpression
    result = eval(compiled, updated_globals, frame.f_locals)
  File "<string>", line 1, in <module>
  File "C:\Python27\Lib\site-packages\sqlalchemy\orm\session.py", line 1245, in delete
    mapperutil.state_str(state))
InvalidRequestError: Instance '<Site at 0x1ed5fb0>' is not persisted

我知道这里发生了什么,但我不确定我应该做什么。

还有其他方法可以从会话中删除尚未持久化的对象吗?或者我应该在尝试删除之前调用session.flush(),以防我要删除的对象尚未刷新?

如果是后者,session.query() 怎么会自动刷新(确保待处理的对象出现在查询结果中),但 session.delete() 没有(这将确保可以删除待处理的对象而不会出错)。

【问题讨论】:

    标签: python sqlalchemy


    【解决方案1】:

    你可以Session.expunge()它。我认为delete() 是这样的理由是,如果您将其发送为待处理,它会担心您不会跟踪事情。但我可以看到故事的另一面,我会考虑的。基本上delete() 所暗示的状态包括一些持久性假设,但它们可能没有我想的那么重要。然后想到了一个“删除或删除”方法,这很有趣,这基本上是我们最初从 Hibernate 复制的“保存或更新”,它只是变成了“添加”。 “add”可以进行transient->pending和detached->persistent的转换——潜在的“remove()”会同时进行pending->transient和persistent->deleted吗?太糟糕了,范围会话已经有“remove()”....

    Session.query() autoflushes 因为它即将到数据库发出一些 SQL 来获取一些行;因此,无论您在本地拥有什么,都需要先出去。 delete() 只是标记对象的状态,因此无需调用任何 SQL。如果我们希望delete() 处理待处理的问题,我们只需更改该断言即可。

    有趣的是,如果你 rollback() 会话,无论你在该会话中 add()'ed 是否被刷新,都会被删除。

    【讨论】:

    • 我同意 Mike 的观点,delete 可能更宽容。但是,当前情况已大大简化 - 可能有其他相关对象被显式或隐式(通过关系)添加到同一会话中并且未提交。因此,IMO,最干净的方法是在会话上做一个rollback()
    • 谢谢,现在说得通了。那么当点击删除按钮时,逻辑应该是怎样的呢?像try: session.delete(foo); except InvalidRequestError: session.expunge(foo) 这样的东西?或者,根据this answer,也许:if has_identity(foo): session.delete(foo); else: session.expunge(foo)?
    • 我可能会说“if object in session.new: expunge else: delete”
    猜你喜欢
    • 2014-02-06
    • 1970-01-01
    • 2014-02-26
    • 1970-01-01
    • 2020-09-17
    • 2013-11-06
    • 2022-10-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多