SQLAlchemy预取列顺序

9 投票
2 回答
8114 浏览
提问于 2025-04-17 17:04

我的模型比较复杂,我想把现有的存储过程里的逻辑转换成SQLAlchemy(为了便于移植)。

不过,我在处理未提交的数据时遇到了困难。

我有一个 user 表:包含用户ID和名字。我还有一个 status 表:包含状态ID和名字。还有一个 user_statuses 表:包含ID、用户ID、状态ID、开始时间和结束时间。

现在,我需要在一个事务中填充这三个表,要么全部成功,要么全部失败。问题是:

user = User(name = 'Test')
status = Status(name = 'Active')
db.session.add(user)
db.session.add(status)

# Oooopa! This is where it fails
user_session = UserStatuses(user_id=user.id, status_id=status.id, datetime.utcnow(), datetime(9999,01,01,00,00,00))
# both user.id and status.id = None as it's uncommited!

基本上,我需要在不使用显式SQL的情况下访问这些表的顺序。为什么呢?因为要便于移植。目前我使用的是PGSQL,可以这样做:

class User(Base):
    ....
    @staticmethod
    def prefetch_id():
        db.session.execute("SELECT NEXTVAL('user_id_seq');").scalar()

如果把数据库引擎换成MySQL,哐当一下!应用就坏了。

有没有什么办法可以做到这一点?要考虑到,这可能是一个高交易量的应用,同时会有成千上万的用户在访问。

2 个回答

19

找到了答案——不知道为什么之前没注意到这一点!

Sequence对象还可以像SQL表达式那样独立执行,这样做的效果就是调用它的“下一个值”功能:

seq = Sequence('some_sequence')
nextid = connection.execute(seq)
4

如果你在添加模型对象后,但在提交之前刷新了会话:

db.session.add(user)
db.session.add(status)
db.session.flush()

那么被add()添加的对象会更新它们的序列列(id),这样user.idstatus.id就不会再是None了。

撰写回答