Search code examples
asynchronoussqlalchemyfastapi

Accessing Queried Result Post Commit in Asynchronous SQLAlchemy creates an Error


So I've been testing something out and noticed that whenever I would access the updated value of some queried result it would throw an error. Take a look at the following code

async def createUser() -> JSONResponse:
    async with Session() as session:
        userRawQuery = await session.execute(
            select(User).filter(User.id == 'some-value')
        )
        user = userRawQuery.scalar()
        # Change Username - For Testing Purposes
        user.username = 'John'
        await session.commit()
        return JSONResponse(
            content = {"msg": "Updated Creator Request"},
            status_code = 200
        )

This code works no problem. But when I do this

return JSONResponse(
    content = {
        "user": {
            "id": user.id,
            "username": user.username,
            "age": user.age
        }
    },
    status_code = 200
)

It creates an error. For some reason accessing the data post commit creates an error. Strange. Any idea why this happens? The Synchronous approach of SQLAlchemy does not present this error but the Asynchronous approach does.

  • Tried to use alternative approach like "query()" method but its not supported for the Asynchronous version of SQLAlchemy

  • Played around with the code to see for certain if doing what I have just presented is what actually creates the error


Solution

  • When a session is committed all the ORM entities associated with the session are expired. If these entities' attributes are accessed after expiry, SQLAlchemy will emit a SELECT to refresh the attribute values.

    In the async case, this is an awaitable operation (the result of the query must be awaited) but in the code in the question the attribute access is not awaited.

    There are two possible solutions:

    • set expire_on_commit=False when creating your sessions.
    • refresh the object (await session.refresh(user)) after committing.

    See the docs on Preventing Implicit IO When Using AsyncSession.