【问题标题】:Does SQLAlchemy save order when adding objects to session?将对象添加到会话时,SQLAlchemy 是否保存顺序?
【发布时间】:2012-04-26 14:45:57
【问题描述】:

这个断言是否总是通过?换句话说,SQLAlchemy 在将新对象添加到会话时是否保存顺序(在生成 INSERT 查询时)?

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm.session import sessionmaker
from sqlalchemy.engine import create_engine
from sqlalchemy.types import Integer
from sqlalchemy.schema import Column

engine = create_engine('sqlite://')
Base = declarative_base(engine)
Session = sessionmaker(bind=engine)
session = Session()

class Entity(Base):
    __tablename__ = 'entity'
    id = Column(Integer(), primary_key=True)
Entity.__table__.create(checkfirst=True)


first = Entity()
session.add(first)

second = Entity()
session.add(second)

session.commit()
assert second.id > first.id
print(first.id, second.id)

没有,在生产中我使用的是 postgresql,sqlite 用于测试。

【问题讨论】:

  • 我既不能在 sqlalchemy 中找到导致这种情况的代码(在很多地方都有 dicts 和 sets),我也不能提出一个引人注目的反例(没有- 序列中的单调性),所以 +1

标签: python database orm sqlalchemy


【解决方案1】:

查看了一下SQLAlchemy源码,插入时看起来像add()记录:https://github.com/zzzeek/sqlalchemy/blob/master/lib/sqlalchemy/orm/session.py#L1719

相关的sn-p:

def _save_impl(self, state):
    if state.key is not None:
        raise sa_exc.InvalidRequestError(
            "Object '%s' already has an identity - it can't be registered "
            "as pending" % state_str(state))

    self._before_attach(state)
    if state not in self._new:
        self._new[state] = state.obj()
        state.insert_order = len(self._new) # THE INSERT ORDER IS SAVED!
    self._attach(state)

这是从Session.add => self._save_or_update_state => self._save_or_update_impl => self._save_impl 调用的。

然后在_sort_states保存时使用:https://github.com/zzzeek/sqlalchemy/blob/master/lib/sqlalchemy/orm/persistence.py#L859

不幸的是,这只是实现级别的证明。我在文档中找不到任何保证它的东西......

更新: 从那以后,我对此进行了更多研究,结果发现 SQLAlchemy 中有一个名为 Unit of Work 的概念,它在一定程度上定义了刷新期间的顺序:http://www.aosabook.org/en/sqlalchemy.html(搜索工作单元)。

在同一个类中,顺序确实是由调用add的顺序决定的。但是,您可能会在不同类之间的 INSERT 中看到不同的排序。如果您添加A 类型的对象a,然后添加B 类型的对象b,但a 原来有一个b 的外键,您将看到@987654338 的INSERT @ 在插入 a 之前。

【讨论】:

  • @zzzeek 在有循环 fk 的情况下是否有办法控制语句的顺序?
【解决方案2】:

不,它会在您提交时执行,而不是在您添加时执行。

【讨论】:

  • 我知道查询是在 flush() 或 commit() 中发送到 db 的。但我猜 sqlalchemy 会按照 session.add() 命令的顺序生成 INSERT 查询。 (我用上面的Entity类和postgres测试过)
  • 是的,它会生成插入查询,但是 id(主键)可以由 db 确定,因为可能有一个在插入时执行的触发器会增加序列 nr 等等。
  • 最初的提问者想知道 INSERT 语句是否在提交时按照添加的顺序发出。赞成,因为我也想知道。 //编辑:想通了!一会儿回答。
猜你喜欢
  • 1970-01-01
  • 2014-08-09
  • 2021-05-28
  • 1970-01-01
  • 2014-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-17
相关资源
最近更新 更多