"implicit combining column" warning not emitting for two columns from two different aliases against same parent table

オープン
#10,960 コメント 4 件 リアクション 1 件 担当者 0 名 GitHub で見る

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

@VimalN2005 がすでに取り組んでいます。

2026年9月19日 から。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
55/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
活発
技術スタック
python, sqlalchemy
領域
database

調査の方向性

まず、提供されている Python の再現コードを SQLite で実行し、次に orm.composite、column_property、および3つのエイリアス付き Bar オブジェクトを使った SQLAlchemy ORM のマッピングを追跡します。issue では、リポジトリのファイルやテストは指定されていません。3つの composite 値が期待される出力と一致し、暗黙的な結合列の警告動作が修正されれば完了です。

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

説明

bug orm
Describe the bug

Description

The following code yields a strange result. I'm expecting bar_1, bar_2, and bar_3 to be mapped as CompositeBar(value_1="a", value_2="b"), CompositeBar(value_1="c", value_2="d"), and CompositeBar(value_1="e", value_2="f") respectively, but actually it ended up with every CompositeBar being CompositeBar(value_1="e", value_2="f") as if it got mapped to bar_alias_3 and the rest were ignored.

BTW the reason why I didn't use relationships here is that the actual code I'm working on has more complex mappings like the composite instance gets mapped to both the table that corresponds to the containing class, and the table that it refers to.

Optional link from https://docs.sqlalchemy.org which documents the behavior that is expected

No response

SQLAlchemy Version in Use

2.0.25

DBAPI (i.e. the database driver)

sqlite3 module

Database Vendor and Major Version

SQLite 2.6.0

Python Version

3.8.16

Operating system

macOS

To Reproduce
import dataclasses

import sqlalchemy as sa
from sqlalchemy import orm


class Base(orm.MappedAsDataclass, orm.DeclarativeBase):
    pass


class Bar(Base):
    __tablename__ = "bar"

    id: orm.Mapped[int] = sa.Column(sa.Integer, primary_key=True)
    value_1: orm.Mapped[str] = sa.Column(sa.String, nullable=False)
    value_2: orm.Mapped[str] = sa.Column(sa.String, nullable=False)


@dataclasses.dataclass
class CompositeBar:
    value_1: str
    value_2: str


foo_table = sa.Table(
    "foo",
    Base.metadata,
    sa.Column("id", sa.Integer, primary_key=True),
    sa.Column("bar_1_id", sa.Integer, sa.ForeignKey(Bar.id), nullable=False),
    sa.Column("bar_2_id", sa.Integer, sa.ForeignKey(Bar.id), nullable=False),
    sa.Column("bar_3_id", sa.Integer, sa.ForeignKey(Bar.id), nullable=False),
)
bar_alias_1 = orm.aliased(Bar)
bar_alias_2 = orm.aliased(Bar)
bar_alias_3 = orm.aliased(Bar)


class Foo(Base):
    __table__ = foo_table.outerjoin(
        bar_alias_1,
        foo_table.c.bar_1_id == bar_alias_1.id
    ).outerjoin(
        bar_alias_2,
        foo_table.c.bar_2_id == bar_alias_2.id
    ).outerjoin(
        bar_alias_3,
        foo_table.c.bar_3_id == bar_alias_3.id
    )

    id: orm.Mapped[int] = orm.column_property(foo_table.c.id)
    _bar_1_id: orm.Mapped[int] = orm.column_property(foo_table.c.bar_1_id, bar_alias_1.id)
    _bar_2_id: orm.Mapped[int] = orm.column_property(foo_table.c.bar_2_id, bar_alias_2.id)
    _bar_3_id: orm.Mapped[int] = orm.column_property(foo_table.c.bar_3_id, bar_alias_3.id)
    bar_1: orm.Mapped[CompositeBar] = orm.composite(CompositeBar, bar_alias_1.value_1, bar_alias_1.value_2)
    bar_2: orm.Mapped[CompositeBar] = orm.composite(CompositeBar, bar_alias_2.value_1, bar_alias_2.value_2)
    bar_3: orm.Mapped[CompositeBar] = orm.composite(CompositeBar, bar_alias_3.value_1, bar_alias_3.value_2)


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

with orm.Session(bind=engine) as session:
    bar_1 = Bar(id=1, value_1="a", value_2="b")
    bar_2 = Bar(id=2, value_1="c", value_2="d")
    bar_3 = Bar(id=3, value_1="e", value_2="f")
    session.add_all([bar_1, bar_2, bar_3])
    session.flush()
    session.execute(sa.insert(foo_table).values([{"id": 1, "bar_1_id": bar_1.id, "bar_2_id": bar_2.id, "bar_3_id": bar_3.id}]))
    foo = session.execute(sa.select(Foo).where(Foo.id == 1)).scalar()
    print(foo)
Error

Actual result:

Foo(id=1, _bar_1_id=1, _bar_2_id=2, _bar_3_id=3, bar_1=CompositeBar(value_1='e', value_2='f'), bar_2=CompositeBar(value_1='e', value_2='f'), bar_3=CompositeBar(value_1='e', value_2='f'))

Expected:

Foo(id=1, _bar_1_id=1, _bar_2_id=2, _bar_3_id=3, bar_1=CompositeBar(value_1='a', value_2='b'), bar_2=CompositeBar(value_1='c', value_2='d'), bar_3=CompositeBar(value_1='e', value_2='f'))
Additional context

No response

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

環境構築

はじめの一歩

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

sqlalchemy/sqlalchemy のほかの issue

sqlalchemy/sqlalchemy の issue をすべて見る

似ている issue

Python の issue をもっと見る

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

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