Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

Session.merge_all() does not suppress autoflush during merge cascade, unlike Session.merge()

クローズ 初心者向け
#13,715 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

  • #13716 @Huang-404-Q による — マージされずにクローズ

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
74/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
python, sqlalchemy, sqlite
領域
databases

調査の方向性

lib/sqlalchemy/orm/session.py:4154 の Session.merge_all() から始め、その動作を Session.merge() および提示された再現例と比較してください。リレーションシップの解決時に autoflush を発生させる merge cascade の回帰テストを追加してください。テストで merge_all() が部分的な状態の flush を回避することを確認し、再現例が IntegrityError なしで成功すれば完了です。

索引モデルが issue の本文から書いたものです。

説明

Session.merge_all() runs its merges outside Session.no_autoflush, while Session.merge() wraps the same _merge call in with self.no_autoflush. When a relationship cascade needs to lazy-load a detached target, the resulting autoflush inserts a half-merged, not-yet-complete object and can violate constraints.

from sqlalchemy import Column, ForeignKey, Integer, String, create_engine, select
from sqlalchemy.orm import DeclarativeBase, Session, relationship

class Base(DeclarativeBase):
    pass

class Parent(Base):
    __tablename__ = "parent"
    id = Column(Integer, primary_key=True)

class Child(Base):
    __tablename__ = "child"
    id = Column(Integer, primary_key=True)
    parent_id = Column(ForeignKey("parent.id"), nullable=False)
    name = Column(String, nullable=False)
    parent = relationship(Parent)

engine = create_engine("sqlite://")
Base.metadata.create_all(engine)

with Session(engine) as session:
    session.add(Parent(id=1))
    session.commit()

with Session(engine) as session:
    parent = session.get(Parent, 1)

with Session(engine) as session:
    child = Child(name="c", parent=parent)
    child.parent_id = None
    session.merge_all([child])   # IntegrityError: NOT NULL constraint failed: child.parent_id
    session.commit()

session.merge(child) in the same position succeeds because it uses no_autoflush.

Expected: merge_all() behaves like merge() and does not flush partially merged state while resolving the relationship. Actual: autoflush emits INSERT INTO child (parent_id, name) VALUES (NULL, NULL) and raises IntegrityError.

Likely cause: Session.merge_all at lib/sqlalchemy/orm/session.py:4154 lacks the with self.no_autoflush: block used by merge().

I have a regression test and a one-line fix ready.

主要言語
Python
スター
12.3k
フォーク
1.8k
平均マージ
1日 2時間
マージ済み PR(30日)
5

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

sqlalchemy/sqlalchemy のほかの issue

sqlalchemy/sqlalchemy の issue をすべて見る

似ている issue

Python の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。