SQLAlchemy 如何从 "aliased" table 加入 table
SQLAlchemy how to join a table from an "aliased" table
我已经在 SO 和 Google 以及官方的 SQLAlchemy 文档中阅读了类似的问题,但仍然无法弄清楚如何解决我的问题。
考虑以下结构(为简单起见删除了 non-relevant 个字段):
header_table = Table(
'header',
metadata,
Column('id', Integer, primary_key=True),
Column('parent_header_id', Integer)
)
item_table = Table(
'item',
dal.metadata,
Column('id', Integer, primary_key=True),
Column('header_id', Integer)
)
class Header:
id: int
parent_header_id: int
# Relationships
items: List[Item]
children: List[Header]
class Item:
id: int
header_id: int
mapper(Header, header_table, properties={
'children': relationship(Header, foreign_keys=[header_table.c.parent_header_id]),
})
总结一下:您可以嵌套 headers(最多 1 层嵌套),每个 header 可以有项目。
我正在尝试加载所有 header 及其项目和 children、 以及 children 的项目。
header_alias = aliased(Header)
records = (
session.query(Header)
.outerjoin(Header.items)
.outerjoin(Header.children.of_type(header_alias))
# .outerjoin(Header.children.of_type(header_alias).items) <<< THE PROBLEM IS HERE (READ BELOW)
.options(contains_eager(Header.items))
.options(contains_eager(Header.children.of_type(header_alias)))
.all()
)
如何加载 children 的项目?
例子中注释掉的代码是错误的,我只是把它放在那里作为我正在尝试做的事情的例子。
注意:上面的代码 有效 ,但它是延迟加载 children 的项目,我正在尝试摆脱这种延迟加载。
非常感谢@zzzeek (Mike Bayer),SQLAlchemy 的作者,他回答了 Github 中的问题。
https://github.com/sqlalchemy/sqlalchemy/discussions/6876
OK you have to alias "items" also, this is SQL so every table has to
be in the FROM clause only once. Here's a full running example
from sqlalchemy import Column
from sqlalchemy import create_engine
from sqlalchemy import ForeignKey
from sqlalchemy import Integer
from sqlalchemy import Table
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import aliased
from sqlalchemy.orm import contains_eager
from sqlalchemy.orm import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy.orm import Session
Base = declarative_base()
metadata = Base.metadata
header_table = Table(
"header",
metadata,
Column("id", Integer, primary_key=True),
Column("parent_header_id", ForeignKey("header.id")),
)
item_table = Table(
"item",
metadata,
Column("id", Integer, primary_key=True),
Column("header_id", ForeignKey("header.id")),
)
class Header(Base):
__table__ = header_table
children = relationship("Header")
items = relationship("Item")
class Item(Base):
__table__ = item_table
id: int
header_id: int
e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)
s = Session(e)
s.add(
Header(
items=[Item(), Item()],
children=[Header(items=[Item()]), Header(items=[Item(), Item()])],
)
)
s.commit()
s.close()
header_alias = aliased(Header)
item_alias = aliased(Item)
records = (
s.query(Header)
.outerjoin(Header.items)
.outerjoin(Header.children.of_type(header_alias))
.outerjoin(header_alias.items.of_type(item_alias))
.options(
contains_eager(Header.items),
contains_eager(Header.children.of_type(header_alias)).options(
contains_eager(header_alias.items.of_type(item_alias))
),
)
.all()
)
s.close()
for r in records:
print(r)
print(r.items)
for c in r.children:
print(c)
print(c.items)
我已经在 SO 和 Google 以及官方的 SQLAlchemy 文档中阅读了类似的问题,但仍然无法弄清楚如何解决我的问题。
考虑以下结构(为简单起见删除了 non-relevant 个字段):
header_table = Table(
'header',
metadata,
Column('id', Integer, primary_key=True),
Column('parent_header_id', Integer)
)
item_table = Table(
'item',
dal.metadata,
Column('id', Integer, primary_key=True),
Column('header_id', Integer)
)
class Header:
id: int
parent_header_id: int
# Relationships
items: List[Item]
children: List[Header]
class Item:
id: int
header_id: int
mapper(Header, header_table, properties={
'children': relationship(Header, foreign_keys=[header_table.c.parent_header_id]),
})
总结一下:您可以嵌套 headers(最多 1 层嵌套),每个 header 可以有项目。
我正在尝试加载所有 header 及其项目和 children、 以及 children 的项目。
header_alias = aliased(Header)
records = (
session.query(Header)
.outerjoin(Header.items)
.outerjoin(Header.children.of_type(header_alias))
# .outerjoin(Header.children.of_type(header_alias).items) <<< THE PROBLEM IS HERE (READ BELOW)
.options(contains_eager(Header.items))
.options(contains_eager(Header.children.of_type(header_alias)))
.all()
)
如何加载 children 的项目?
例子中注释掉的代码是错误的,我只是把它放在那里作为我正在尝试做的事情的例子。
注意:上面的代码 有效 ,但它是延迟加载 children 的项目,我正在尝试摆脱这种延迟加载。
非常感谢@zzzeek (Mike Bayer),SQLAlchemy 的作者,他回答了 Github 中的问题。
https://github.com/sqlalchemy/sqlalchemy/discussions/6876
OK you have to alias "items" also, this is SQL so every table has to be in the FROM clause only once. Here's a full running example
from sqlalchemy import Column
from sqlalchemy import create_engine
from sqlalchemy import ForeignKey
from sqlalchemy import Integer
from sqlalchemy import Table
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import aliased
from sqlalchemy.orm import contains_eager
from sqlalchemy.orm import declarative_base
from sqlalchemy.orm import relationship
from sqlalchemy.orm import Session
Base = declarative_base()
metadata = Base.metadata
header_table = Table(
"header",
metadata,
Column("id", Integer, primary_key=True),
Column("parent_header_id", ForeignKey("header.id")),
)
item_table = Table(
"item",
metadata,
Column("id", Integer, primary_key=True),
Column("header_id", ForeignKey("header.id")),
)
class Header(Base):
__table__ = header_table
children = relationship("Header")
items = relationship("Item")
class Item(Base):
__table__ = item_table
id: int
header_id: int
e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)
s = Session(e)
s.add(
Header(
items=[Item(), Item()],
children=[Header(items=[Item()]), Header(items=[Item(), Item()])],
)
)
s.commit()
s.close()
header_alias = aliased(Header)
item_alias = aliased(Item)
records = (
s.query(Header)
.outerjoin(Header.items)
.outerjoin(Header.children.of_type(header_alias))
.outerjoin(header_alias.items.of_type(item_alias))
.options(
contains_eager(Header.items),
contains_eager(Header.children.of_type(header_alias)).options(
contains_eager(header_alias.items.of_type(item_alias))
),
)
.all()
)
s.close()
for r in records:
print(r)
print(r.items)
for c in r.children:
print(c)
print(c.items)