【问题标题】:SQLAlchemy with multiple session, how to avoid "Object is already attached to session X"?具有多个会话的 SQLAlchemy,如何避免“对象已附加到会话 X”?
【发布时间】:2021-11-27 16:27:11
【问题描述】:

我有一个特殊的配置,我从 sessionmaker 创建了两个 SQLAlchemy 会话:

db.read = sessionmaker(autoflush=False)
db.write = sessionmaker()

调用db.write.add(obj)时,有时会出现以下错误(但并非总是如此):

sqlalchemy.exc.InvalidRequestError: 对象“”已附加到会话“14”(这是“15”)

有没有办法做到以下几点:

"如果session是db.write,那么调用db.write.add(obj) 否则,将 obj 添加到 db.write session 以保存它,并且(重要)更新 db.write session 和 db.read session 中的对象"

(我已经设法通过写入保存到,但是 db.read 中的 obj.id 为空)

感谢您的帮助

【问题讨论】:

  • 您能提供重现您的问题的示例代码吗?

标签: python python-3.x sqlalchemy


【解决方案1】:

我们可以通过扩展Session.add 来检测和处理对象已经在另一个会话中的情况,并通过添加事件侦听器以在对象被提交后将其恢复到读取会话中来近似期望的行为。一个对象不可能同时存在于两个会话中:如果希望对象保留在写入会话中,则不需要侦听器和 _prev_session 属性。

import weakref

import sqlalchemy as sa
from sqlalchemy import orm

...

class CarefulSession(orm.Session):
    def add(self, object_):
        # Get the session that contains the object, if there is one.
        object_session = orm.object_session(object_)
        if object_session and object_session is not self:
            # Remove the object from the other session, but keep
            # a reference so we can reinstate it.
            object_session.expunge(object_)
            object_._prev_session = weakref.ref(object_session)
        return super().add(object_)

# The write session must use the Session subclass; the read 
# session need not.
WriteSession = orm.sessionmaker(engine, class_=CarefulSession)


@sa.event.listens_for(WriteSession, 'after_commit')
def receive_after_commit(session):
    """Reinstate objects into their previous sessions."""
    objects = filter(lambda o: hasattr(o, '_prev_session'), session.identity_map.values())
    for object_ in objects:
        prev_session = object_._prev_session()
        if prev_session:
            session.expunge(object_)
            prev_session.add(object_)
            delattr(object_, '_prev_session')

一个完整的实现可能会添加一个after_rollback 侦听器,并可能在基本模型的__init__ 中初始化_prev_session 以避免del/has attr 调用。

【讨论】:

  • 哇,太棒了!谢谢你!如果您有时间,我还尝试将 Select 实例保存在模型中并比较两个 Select 以查看它们是否是 stackoverflow.com/questions/69634315/… 的相同查询。再次感谢!
猜你喜欢
  • 2014-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-08
  • 1970-01-01
  • 2013-08-26
  • 1970-01-01
相关资源
最近更新 更多