簡體   English   中英

SQLAlchemy 次要關系不使用 JOIN

[英]SQLAlchemy secondary relationship not using JOIN

我在 SQLAlchemy 上創建了多對多關系,但由於某種原因,當我訪問它時,它不會發出 JOIN 子句,而是從三個表的叉積中選擇並使用WHERE子句進行過濾。 我不明白為什么會這樣,以及如何解決它。

這是關聯表和主模型的 python 代碼。 輔助模型過於復雜,我認為它具有skuaccount_id列的事實,這些列具有索引(並且一起是 PK 的一部分),這足以繼續進行

product_info_to_product_profile_association_table = Table(
    "tpl_products_to_product_profiles_r1",
    metadata,
    sa.Column(
        "sku",
        sa.String(128),
# This FK is failing at the MySQL level
        # sa.ForeignKey(ProductInfo.sku),
        nullable=False,
    ),
    sa.Column(
        "account_id", mysql.INTEGER(11), sa.ForeignKey(ProductInfo.account_id), nullable=False
    ),
    sa.Column(
        "product_profile_id",
        mysql.INTEGER(11, unsigned=True),
        sa.ForeignKey("tpl_product_profiles.id"),
        nullable=False,
    ),
    sa.UniqueConstraint("sku", "account_id", "product_profile_id", name="product_unique"),
)
​
​
class ProductProfile(BillingBaseModel):
​
    __tablename__ = "tpl_product_profiles"
​
    id = sa.Column(mysql.INTEGER(11, unsigned=True), primary_key=True)
    name = sa.Column(sa.String(90), nullable=False)
    account_id = sa.Column(mysql.INTEGER(11), sa.ForeignKey(Account.id), nullable=False)
​
    product_infos = orm.relationship(
        ProductInfo,
        secondary=product_info_to_product_profile_association_table,
        secondaryjoin=sa.and_(
            ProductInfo.sku
            == orm.foreign(product_info_to_product_profile_association_table.c.sku),
            ProductInfo.account_id
            == orm.foreign(product_info_to_product_profile_association_table.c.account_id),
        ),
        secondaryjoin=(
            id
            == orm.foreign(product_info_to_product_profile_association_table.c.product_profile_id)
        ),
        backref=orm.backref("product_profile", uselist=False),
    )

這是我嘗試通過實例訪問關系時生成的 SQL

>>> pp.product_infos

[SELECT product_info.sku..........
FROM product_info, tpl_products_to_product_profiles_r1 
WHERE tpl_products_to_product_profiles_r1.product_profile_id = %s AND product_info.sku = tpl_products_to_product_profiles_r1.sku AND product_info.account_id = tpl_products_to_product_profiles_r1.account_id]
[parameters: (6L,)]

這可能不是最好的答案,但我已經深入研究了 sqlalchemy 的一些內部工作,它在執行延遲加載時顯式創建了交叉連接

        if self.parent_property.secondary is not None:
            q.add_criteria(
                lambda q: q.select_from(
                    self.mapper, self.parent_property.secondary
                )
            )

我發現的最佳解決方案是使用某種急切加載。

不管那是

  • 關系定義中的lazy='selectin'
  • 在查詢 ProductProfile 對象時添加selectinload(ProductProfile.product_infos)並知道您將需要訪問該屬性
  • 或執行與上述相同的操作,但顯式定義查詢中的連接並使用contains_eager(ProductProfile.product_infos)

對於前兩種情況,sqlalchemy 建議您在處理x-to-many表時使用selectinsubquery預加載(尤其是當 many 表很大時): https://docs.sqlalchemy.org/en/14/orm/loading_relationships。 html#what-kind-of-loading-to-use

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM