异步 SQLalchemy:访问急切加载的空关系会触发新的延迟加载,引发错误
Async SQLalchemy: accessing eagerly-loaded empty relationship triggers new lazy-load, raising error
我正在使用 sqlalchemy + asyncpg,并且 'selectin' 预先加载。
我有与朋友有一对多关系的个人项目。
我将一个人插入到我的数据库中,没有相关的朋友条目。如果在同一个会话中我尝试从数据库中获取那个人,我可以很好地访问他们的静态(非关系)列,但无法访问 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)
解决方法是在get
中使用populate_existing
参数:
populate_existing – causes the method to unconditionally emit a SQL query and refresh the object with the newly loaded data, regardless of whether or not the object is already present.
替换
created_person = await session.get(person, person_id)
和
created_person = await session.get(person, person_id, populate_existing=True)
我正在使用 sqlalchemy + asyncpg,并且 'selectin' 预先加载。
我有与朋友有一对多关系的个人项目。
我将一个人插入到我的数据库中,没有相关的朋友条目。如果在同一个会话中我尝试从数据库中获取那个人,我可以很好地访问他们的静态(非关系)列,但无法访问 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)
解决方法是在get
中使用populate_existing
参数:
populate_existing – causes the method to unconditionally emit a SQL query and refresh the object with the newly loaded data, regardless of whether or not the object is already present.
替换
created_person = await session.get(person, person_id)
和
created_person = await session.get(person, person_id, populate_existing=True)