如何阻止SQLAlchemy中关联对象A随B持久化?
解决方案
核心问题
翻译后的A实例仍处于SQLAlchemy会话的跟踪范围内,提交B的修改时,会话会自动同步所有被跟踪对象的变更,导致翻译后的A被意外持久化。
有效解决方法
1. 将翻译用的A实例从会话中脱管
在翻译前把A实例从主会话中移除,后续修改不会被会话跟踪,提交B时就不会连带保存A的变更:
# some_service.py def get_by_id(a_id): a = A.get_by_id(a_id) if a: # 从会话中移除实例,停止跟踪其变更 db.session.expunge(a) return translate(a)
2. 使用临时会话获取翻译用的A实例
创建独立的临时会话查询A并翻译,临时会话中的对象和主会话完全隔离,不会影响主会话的提交:
# some_service.py def get_by_id(a_id): # 基于会话工厂创建临时会话 temp_session = db.session_factory() try: a = temp_session.query(A).get(a_id) if a: return translate(a) finally: # 关闭临时会话,释放资源 temp_session.close()
3. 将A实例转为非映射状态
使用SQLAlchemy的make_transient方法,把映射实例转为普通对象,彻底脱离会话跟踪:
from sqlalchemy.orm import make_transient # some_service.py def get_by_id(a_id): a = A.get_by_id(a_id) if a: # 移除实例的会话关联和映射状态,变为普通对象 make_transient(a) return translate(a)
为什么之前的尝试无效
- 修改
cascade属性仅控制关联对象的级联操作,但只要A实例仍在会话中被跟踪,提交时就会被同步; - 简单复制A实例如果未彻底脱离会话关联,复制后的对象可能仍被会话间接跟踪,导致变更被提交。
内容的提问来源于stack exchange,提问作者Giovanni Cabrera
相关产品推荐
相关产品推荐

