私の知る限り、ORMに一括挿入を発行させる方法はありません。根本的な理由は、SQLAlchemyが各オブジェクトのID(つまり、新しい主キー)を追跡する必要があり、一括挿入がそれを妨害するためだと思います。たとえば、foo
テーブルにid
列が含まれ、Foo
クラスにマップされているとします。
x = Foo(bar=1)
print x.id
# None
session.add(x)
session.flush()
# BEGIN
# INSERT INTO foo (bar) VALUES(1)
# COMMIT
print x.id
# 1
SQLAlchemyはx.id
別のクエリを発行せずに値を取得したため、INSERT
ステートメントから直接値を取得したと推測できます。同じインスタンスを介して作成されたオブジェクトに後でアクセスする必要がない場合は、挿入のORMレイヤーをスキップできます。
Foo.__table__.insert().execute([{'bar': 1}, {'bar': 2}, {'bar': 3}])
# INSERT INTO foo (bar) VALUES ((1,), (2,), (3,))
SQLAlchemyはこれらの新しい行を既存のオブジェクトと一致させることができないため、後続の操作のためにそれらを新たにクエリする必要があります。
古いデータに関する限り、セッションには、データベースがセッション外で変更された時期を知る方法が組み込まれていないことを覚えておくと役に立ちます。既存のインスタンスを介して外部で変更されたデータにアクセスするには、インスタンスに期限切れのマークを付ける必要があります。これはデフォルトではsession.commit()
で発生しますが、session.expire_all()
またはを呼び出すことで手動で実行できますsession.expire(instance)
。例(SQLは省略):
x = Foo(bar=1)
session.add(x)
session.commit()
print x.bar
# 1
foo.update().execute(bar=42)
print x.bar
# 1
session.expire(x)
print x.bar
# 42
session.commit()
が期限切れx
になるため、最初のprintステートメントは暗黙的に新しいトランザクションを開き、x
の属性を再クエリします。最初の印刷ステートメントをコメントアウトすると、新しいクエリが更新されるまで発行されないため、2番目のステートメントが正しい値を取得するようになります。
これは、トランザクションの分離という観点からは理にかなっています。トランザクション間の外部の変更のみを取得する必要があります。これにより問題が発生する場合は、すぐにに到達するのではなく、アプリケーションのトランザクション境界を明確にするか、再考することをお勧めしますsession.expire_all()
。