异步 SQLalchemy:访问急切加载的空关系会触发新的延迟加载,引发错误

Posted

技术标签:

【中文标题】异步 SQLalchemy:访问急切加载的空关系会触发新的延迟加载,引发错误【英文标题】:Async SQLalchemy: accessing eagerly-loaded empty relationship triggers new lazy-load, raising error 【发布时间】:2021-12-03 20:50:51 【问题描述】:

我正在使用 sqlalchemy + asyncpg,并“选择”预加载。

我的 Person 项目与 Friends 具有一对多关系。

我将一个 Person 插入到我的数据库中,但没有相关的 Friend 条目。如果在同一个会话中我尝试从数据库中获取该 Person,我可以正常访问其静态(非关系)列,但无法访问 friends 关系。

我认为尝试访问person.friends 会触发延迟加载,尽管之前它是作为selectin 加载执行的。为什么是这样?如何避免?

# Create the ORM model
class Person(Base):
    __tablename__ = 'items'
    id_ = Column(POSTGRES_UUID(as_uuid=True), primary_key=True)
    name = Column(String(32))
    friends = relationship('Friend', lazy='selectin')

# Create an instance
person_id = uuid4()
person = Person(id_=person_id, name='Alice') # Note that this Person's friends are not set

# Add to database
async with AsyncSession(engine, expire_on_commit=False) as session:
    try:
        session.begin()
        session.add(person)
        await session.commit()
    except:
        await session.rollback()
        raise
    # Get the added person from the database
    created_person = await session.get(person, person_id)
    print(created_person.id_) # Works fine
    print(created_person.friends) # Raises error

错误:

sqlalchemy.exc.MissingGreenlet: greenlet_spawn has not been called; can't call await_() here.
Was IO attempted in an unexpected place? (Background on this error at: https://sqlalche.me/e/14/xd2s)

【问题讨论】:

【参考方案1】:

解决方法是使用get中的populate_existing参数:

populate_existing – 使方法无条件地发出 SQL 查询并用新加载的数据刷新对象,无论对象是否已经存在。

替换

created_person = await session.get(person, person_id)

created_person = await session.get(person, person_id, populate_existing=True)

session.get documentation

另见:https://github.com/sqlalchemy/sqlalchemy/issues/7176

【讨论】:

以上是关于异步 SQLalchemy:访问急切加载的空关系会触发新的延迟加载,引发错误的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 动态关系 - 在急切加载时访问模型属性

忽略急切加载的数据的空对象 - laravel

如何访问与异步 sqlalchemy 的关系?

尝试从子模型重新访问父模型的 laravel 多级关系急切加载问题

如何在 has_many 关系中急切加载最新的对象?

急切加载关系