在SQLAlchemy会话中删除尚未持久化的对象
我的应用程序允许用户创建和删除 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()
不会(这本来可以确保待处理的对象可以无错误地删除)?
1 个回答
你可以用 Session.expunge()
来处理它。我觉得 delete()
之所以这样设计,是因为它担心你在处理待处理状态时没有好好跟踪这些东西。不过我也能理解另一种看法,我会考虑一下。基本上,delete()
所暗示的状态包含了一些持久化的假设,但这些假设可能没有我想的那么重要。于是我想到一个“清除或删除”的方法,这听起来有点搞笑,因为这基本上就是我们最初从 Hibernate 复制过来的“保存或更新”,后来变成了“添加”。“添加”可以处理从临时状态到待处理状态,以及从分离状态到持久状态的转换——那么一个潜在的“移除(remove)”方法是否可以同时处理待处理到临时和持久到删除的转换呢?可惜的是,作用域会话已经有了“移除(remove)”这个方法……
Session.query()
会自动刷新,因为它准备要去数据库发出一些 SQL 查询来获取数据行;所以你本地的任何数据都需要先发送出去。delete()
只是标记了一个对象的状态,所以不需要执行任何 SQL。如果我们想让 delete()
在待处理状态下也能工作,我们只需要改变这个假设。
有趣的是,如果你对会话执行 rollback()
,在这个会话中你用 add()
添加的所有内容,无论是否已经刷新,都会被清除。