![](/img/trans.png)
[英]SQLAlchemy Joining a Session into an External Transaction Not Working as Expected
[英]Python/SqlAlchemy joining table to itself not generating expected query
我想做的事情似乎應該很簡單。 我想將代表數據收集站的表連接到自身,以便跟蹤部署在同一位置的站的先前迭代。
在下面的代碼中,我有兩個類:StationTable 和 StationTypeTable。 StationTable 有兩個 FK 關系——一個到站類型,另一個回到站表。
最后是生成的 SQL,它顯示了對 StationType 表的正確連接,但沒有任何痕跡由 previous_station 列創建的鏈接。
我究竟做錯了什么? 請注意,這最終將與 FastApi 和 Async Postgres 驅動程序一起使用,這可能會或可能不會引起人們的興趣。 另外,我不需要通過關系修改相關表; 我只需要讀取一些屬性。
使用 SQLAlchemy 1.4,最新版本。
from typing import Any
import sqlalchemy as sa
from sqlalchemy import select
from sqlalchemy.orm import registry, RelationshipProperty
from sqlalchemy.schema import ForeignKey
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm.decl_api import DeclarativeMeta
mapper_registry = registry()
class BaseTable(metaclass=DeclarativeMeta):
__abstract__ = True
registry = mapper_registry
metadata = mapper_registry.metadata
__init__ = mapper_registry.constructor
id = sa.Column(UUID(as_uuid=True), primary_key=True, server_default=sa.text("gen_random_uuid()"))
class Relationship(RelationshipProperty): # type: ignore
""" Using this class hides some of the static typing messiness in SQLAlchemy. """
inherit_cache = True # If this works, should improve performance
def __init__(self, *args: Any, **kwargs: Any):
if "lazy" not in kwargs:
# 'joined' means items should be loaded "eagerly" in the same query as that of the parent, using a JOIN or LEFT
# OUTER JOIN. Whether the join is "outer" or not is determined by the relationship.innerjoin parameter.
# We need this to keep loading in async mode from blowing up.
# https://docs.sqlalchemy.org/en/14/orm/relationship_api.html
kwargs["lazy"] = "joined"
super().__init__(*args, **kwargs)
class StationTypeTable(BaseTable):
__tablename__ = "station_type"
name = sa.Column(sa.String(255), unique=True, nullable=False)
description = sa.Column(sa.UnicodeText)
class StationTable(BaseTable):
__tablename__ = "station"
name = sa.Column(sa.String(255), unique=True, nullable=False)
installation_date = sa.Column(sa.BigInteger, nullable=False)
station_type_id = sa.Column(UUID(as_uuid=True), ForeignKey(StationTypeTable.id), nullable=False)
previous_station = sa.Column(UUID(as_uuid=True), ForeignKey("station.id"), nullable=True)
station_type_table = Relationship(StationTypeTable, uselist=False)
previous_station_table = Relationship("StationTable", uselist=False) # self join, uselist=False ==> one-to-one
query = select(StationTable)
print(query)
# SELECT station.id, station.name, station.installation_date, station.station_type_id, station.previous_station,
# station_type_1.id AS id_1, station_type_1.name AS name_1, station_type_1.description
# FROM station
# LEFT OUTER JOIN station_type AS station_type_1 ON station_type_1.id = station.station_type_id
編輯:
根據下面 Ian Wilson 的回復,我將參數join_depth=1
添加到 previous_station_table 關系,這確實為關系生成了 SQL,但奇怪的是,與 station_type_table 關系相比,它是“錯誤的方式”。 這是使用該參數生成的 SQL:
SELECT station.id, station.name, station.installation_date,
station.station_type_id, station.previous_station,
station_type_1.id AS id_1, station_type_1.name AS name_1,
station_type_1.description, station_type_2.id AS id_2,
station_type_2.name AS name_2, station_type_2.description AS description_1,
station_1.id AS id_3, station_1.name AS name_3,
station_1.installation_date AS installation_date_1,
station_1.station_type_id AS station_type_id_1,
station_1.previous_station AS previous_station_1
FROM station
LEFT OUTER JOIN station_type AS station_type_1
ON station_type_1.id = station.station_type_id -- looks right
LEFT OUTER JOIN station AS station_1
ON station.id = station_1.previous_station -- looks backward, see below
LEFT OUTER JOIN station_type AS station_type_2
ON station_type_2.id = station_1.station_type_id
我認為標記的行應該是:
LEFT OUTER JOIN station AS station_1 ON station.previous_station = station_1.id
問題似乎是您必須為自引用預加載設置join_depth
,我將其設置為join_depth=1
並且這似乎修復了查詢。 由於您有一個額外的急切加入,這實際上會創建 3 個加入而不是 2 個加入,因為第二組站也必須加入類型。 該文檔在此處解釋了join_depth
:
這里簡要解釋了relatoinship
的參數:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.