【发布时间】:2021-11-27 09:19:54
【问题描述】:
在我们的系统中,我们有实体 Item 和 Store,它们与 Stock 实体相关。 一件商品可以存放在多个商店,也可以存放多个商品在一个商店,所以是简单的多对多关系。
但是,当使用辅助参考描述这种关系时:
stores = relationship(
'Store',
secondary='stock',
backref='items'
)
SQLAlchemy 会加载该相关 Store 的所有袜子,而不仅仅是那些与引用项目相关的袜子。
例如。当我们指定一个生成以下 sql 的关系时:
SELECT item.id AS item_id, store.id AS store_id, stock.id AS stock_id, stock.store_id AS stock_store_id, stock.item_id AS stock_item_id
FROM item
LEFT OUTER JOIN (stock AS stock_1 JOIN store ON store.id = stock_1.store_id) ON item.id = stock_1.item_id
LEFT OUTER JOIN stock ON store.id = stock.store_id AND stock.item_id = item.id
WHERE stock.item_id = item.id
返回以下数据:
item_id, store_id, stock_id, stock_store_id, stock_item_id,
1, 1, 1, 1, 1
2, 1, 2, 1, 2
1, 2, 3, 2, 1
2, 2, 4, 2, 2
实际加载的数据如下:
items = [{
id: 1,
stores: [
{
id: 1,
stocks: [
{ id: 1, item_id: 1 },
{ id: 2, item_id: 2 } <- should not be loaded items[0].id != 2
]
},
{
id: 2,
stocks: [
{ id: 3, item_id: 1 },
{ id: 4, item_id: 2 } <- should not be loaded items[0].id != 2
]
}
]
},
{
id: 2,
stores: [
{
id: 1,
stocks: [
{ id: 2, item_id: 2 },
{ id: 1, item_id: 1 } <- should not be loaded items[1].id != 1
]
},
{
id: 2,
stocks: [
{ id: 4, item_id: 2 },
{ id: 3, item_id: 1 } <- should not be loaded items[1].id != 1
]
}
]
}]
作为参考,请查看实体及其关系的声明以及查询对象:
Base = declarative_base()
class Item(Base):
__tablename__ = 'item'
id = Column(Integer, primary_key=True)
stores = relationship(
'Store',
secondary='stock',
backref='items'
)
class Store(Base):
__tablename__ = 'store'
id = Column(Integer, primary_key=True)
class Stock(Base):
__tablename__ = 'stock'
id = Column(Integer, primary_key=True)
store_id = Column(Integer, ForeignKey(Store.id), nullable=False)
item_id = Column(Integer, ForeignKey(Item.id), nullable=False)
item = relationship(Item, backref='stocks')
store = relationship(Store, backref='stocks')
items = session.query(
Item
).outerjoin(
Item.stores,
(Stock, and_(Store.id == Stock.store_id, Stock.item_id == Item.id))
).filter(
Stock.item_id == Item.id,
).options(
contains_eager(
Item.stores
).contains_eager(
Store.stocks
)
).all()
【问题讨论】:
标签: python postgresql sqlalchemy flask-sqlalchemy eager-loading