You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 02:45:06