SQLAlchemy在将对象添加到会话中时是否保存顺序?

18

这个断言是否总是通过?换句话说,当将新对象添加到会话中时,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仅用于测试。


1
我既找不到在SQLAlchemy中导致这种情况的代码(它的 dictset 出现在很多地方),也无法提供一个令人信服的反例(除了序列中的非单调性),所以 +1。 - SingleNegationElimination
2个回答

19
在查看SQLAlchemy源代码后,似乎add()会在插入时记录被插入的记录:https://github.com/zzzeek/sqlalchemy/blob/master/lib/sqlalchemy/orm/session.py#L1719 相关的片段:
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中有一个叫做工作单元的概念,它在某种程度上定义了刷新期间的顺序:http://www.aosabook.org/en/sqlalchemy.html(搜索“Unit of Work”)。在同一个类中,顺序确实由调用add的顺序确定。但是,在不同的类之间可能会看到不同的INSERT排序。如果您添加类型为A的对象a,然后稍后添加类型为B的对象b,但a实际上具有对b的外键,则会在a的INSERT之前看到b的INSERT。

1
@zzzeek有没有办法在存在循环外键的情况下控制语句的顺序? - Alex Rothberg

-3
不,它们是在你提交时执行的,而不是在你添加时执行。

我知道查询会在flush()或commit()时发送到数据库。但我猜想sqlalchemy会按照session.add()命令的顺序生成INSERT查询。(我用上述实体类和postgres进行了测试) - Taha Jahangir
是的,它生成插入查询,但是id(主键)可以由数据库确定,因为可能会有在插入时执行增加序列号等操作的触发器。 - rapadura
1
原始提问者想知道在提交时是否按照添加顺序发出INSERT语句。我也很好奇,所以点了赞。//编辑:我弄清楚了!马上回答。 - munchybunch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接