Sqlalchemy:解决与自定义 Primaryjoin 的多对多关系的笛卡尔积警告

til*_*151 7 sqlalchemy cartesian-product relationship composite-primary-key window-functions

假设我有以下数据库架构:

class A(Base):
    __tablename__ = "a_table"

    id = Column(Integer, primary_key=True, autoincrement=True)
    version = Column(Integer, primary_key=True, default=1)

    # More columns...

    bs = relationship(
        "B", secondary="a2b_table", back_populates="as"
    )

class B(Base):
    __tablename__ = "b_table"

    id = Column(Integer, primary_key=True)

    as = relationship(
        A, secondary="a2b_table", back_populates="bs"
    )

class A2B(Base):
    __tablename__ = "a2b_table"

    a_id = Column(
        Integer(),
        primary_key=True,
    )
    a_version = Column(
        Integer,
        primary_key=True,
    )
    b_id = sa.Column(
        Integer,
        ForeignKey("b.id", name="b_fk"),
        primary_key=True,
    )

    __table_args__ = (
        ForeignKeyConstraint(
            [a_id, a_version],
            [A.id, A.version],
            name="a_fk",
        ),
        {},
    )
    
Run Code Online (Sandbox Code Playgroud)

每个A版本都由 标识,id并且可以有多个版本。如果 的列A(未显示的列)发生变化,我会生成一个A具有相同id和 的新列version+1。该关系bs为我提供了B与特定版本的A.

问题是,该关系as为我提供了A与特定B. 相反,我希望该关系仅包含每个 的最新(最高)版本A。按照文档,我尝试使用自定义函数primaryjoin和窗口函数来解决此问题:

partition = select(
    A,
    row_number()
    .over(order_by=A.version.desc(), partition_by=A.id)
    .label("index"),
).alias()

partitioned_as = aliased(A, partition)

B.latest_as = relationship(
    partitioned_as,
    primaryjoin=and_(
        partition.c.index == 1,
        and_(
            partitioned_as.id == A2B.a_id,
            partitioned_as.version == A2B.a_version,
        ),
    ),
    secondary="a2b_table",
    viewonly=True,
)
Run Code Online (Sandbox Code Playgroud)

不幸的是,它不起作用,我收到警告:

SELECT 语句在 FROM 元素“anon_1”、“a2b_table”和 FROM 元素“a_table”之间具有笛卡尔积。在每个元素之间应用连接条件以进行解析。

我检查了 sqlalchemy 生成的 SQL 语句,它的 FROM 子句中有 ,即,anon_1的查询。据我了解,不应该出现在该语句的 FROM 子句中,因为它已经位于 的 FROM 子句中。我不知道如何摆脱它。partitiona_tablea_tablepartition

有人能指出我正确的方向吗?提前致谢。