SQLAlchemy:使用 sessionmaker 作为上下文管理器强制手动删除
SQLAlchemy: Using sessionmaker as contextmanger forces to expunge manually
我正在使用 SQLAlchemy 并尝试将 sessionmaker 用作我的事务的上下文管理器(在 documentation 之后):
Session = sessionmaker(some_engine)
with Session.begin() as session:
query = session.query(SomeTable)
an_entry = query.one()
# session.expunge_all() # Fixes the exception
an_entry.attribute
这会引发 sqlalchemy.orm.exc.DetachedInstanceError: Instance <AnEntry at 0x7f0a9d1c2560> is not bound to a Session
异常。这可以通过删除上下文管理器中的内容来解决(请参阅上面注释掉的行)。
我对这种行为感到惊讶,因为 SQLAlchemy documentation 和代码表明关闭会话会自动清除所有 ORM 对象。事实上,以下等效于上述工作,而无需我手动删除:
Session = sessionmaker(some_engine)
session = Session()
with session.begin():
query = session.query(SomeTable)
an_entry = query.one()
an_entry.attribute
谁能解释这种行为?
在第二个“工作”示例中,上下文管理器是 session.begin
返回的 SessionTransaction
对象,而不是会话本身。在访问属性之前会话未关闭,因此没有 DetachedInstanceError
:实例永远不会被删除。
更好的比较可能是此代码不引发错误的原因:
with Session() as s:
an_entry = s.query(SomeTable).one()
an_entry.attribute
原因是它没有提交。默认情况下,ORM 对象在提交时过期,因此后续的属性访问需要查询才能获取值。在 with Session.begin() as session:
的情况下,会话在离开 with 块时提交,因此访问属性需要查询,这需要将对象附加到会话。
Session
和 sessionmaker
都接受 expire_on_commit
布尔关键字参数来控制此行为。
我正在使用 SQLAlchemy 并尝试将 sessionmaker 用作我的事务的上下文管理器(在 documentation 之后):
Session = sessionmaker(some_engine)
with Session.begin() as session:
query = session.query(SomeTable)
an_entry = query.one()
# session.expunge_all() # Fixes the exception
an_entry.attribute
这会引发 sqlalchemy.orm.exc.DetachedInstanceError: Instance <AnEntry at 0x7f0a9d1c2560> is not bound to a Session
异常。这可以通过删除上下文管理器中的内容来解决(请参阅上面注释掉的行)。
我对这种行为感到惊讶,因为 SQLAlchemy documentation 和代码表明关闭会话会自动清除所有 ORM 对象。事实上,以下等效于上述工作,而无需我手动删除:
Session = sessionmaker(some_engine)
session = Session()
with session.begin():
query = session.query(SomeTable)
an_entry = query.one()
an_entry.attribute
谁能解释这种行为?
在第二个“工作”示例中,上下文管理器是 session.begin
返回的 SessionTransaction
对象,而不是会话本身。在访问属性之前会话未关闭,因此没有 DetachedInstanceError
:实例永远不会被删除。
更好的比较可能是此代码不引发错误的原因:
with Session() as s:
an_entry = s.query(SomeTable).one()
an_entry.attribute
原因是它没有提交。默认情况下,ORM 对象在提交时过期,因此后续的属性访问需要查询才能获取值。在 with Session.begin() as session:
的情况下,会话在离开 with 块时提交,因此访问属性需要查询,这需要将对象附加到会话。
Session
和 sessionmaker
都接受 expire_on_commit
布尔关键字参数来控制此行为。