SQLAlchemy:对象过期后session.get的joinedload函数失效问题
问题:为何对象过期后session.get无法完成joinedload操作?
模型定义
class Model: id = Column(Integer, primary_key=True) rel = relationship(Submodel)
两种测试场景
场景1:使用session.get带joinedload选项
model = self.session.get(Model, 1) model.field = 'any' self.session.flush() return self.session.get(Model, 1, options=[joinedload("*")])
现象:会为模型的每个关系发起单独查询。
场景2:使用select查询带joinedload选项
model = self.session.get(Model, 1) model.field = 'any' self.session.flush() return self.session.scalars( select(Model) .options(joinedload("*")) .where(Model.id == 1) ).one()
现象:正常,仅发起一次关联查询。
原因解析
这是SQLAlchemy中session.get()的设计逻辑决定的:
- 首次调用
session.get(Model, 1)时,对象已被存入会话的标识映射(identity map)。 - 修改字段并执行
flush后,该对象会被标记为过期——此时会话缓存的对象状态与数据库中的数据可能存在差异。 - 再次调用
session.get()时,SQLAlchemy会优先从标识映射中取出这个过期对象,仅刷新它的基础属性,但joinedload这类关联加载选项仅在首次加载对象时生效,刷新操作不会应用这些选项。后续访问关联属性时,只能触发懒加载,每个关系都会发起单独查询。
而使用select()语句查询时,SQLAlchemy会直接执行包含关联预加载的完整SQL查询,不会复用标识映射中已有的过期对象,因此能一次性加载所有关联数据。
内容的提问来源于stack exchange,提问作者Masta
相关产品推荐
相关产品推荐

