我有一个类似于以下的数据模型:
Location 1-----*<> Vacation <>*------1 TravelAgency
<>
|*
|
|1
Airline
它以正常方式在sqlalchemy中实现:
class Vacation(Base):
__tablename__ = 'vacation'
id = Column(Integer, primary_key=True)
location_id = Column(Integer, ForeignKey('location.id')
location = relationship("Location")
travel_agency_id = Column(Integer, ForeignKey('travel_agency.id')
travel_agency = relationship("TravelAgency")
airline_id = Column(Integer, ForeignKey('airline.id')
airline = relationship("Airline")
class Location(Base):
__tablename__ = 'location'
id = Column(Integer, primary_key=True)
data = Column(Integer)
class TravelAgency(Base):
__tablename__ = 'travel_agency'
id = Column(Integer, primary_key=True)
data = Column(Integer)
class Airline(Base):
__tablename__ = 'airline'
id = Column(Integer, primary_key=True)
data = Column(Integer)
由于需要多个连接,分析数亿个对象的数据库中的假期太慢。在使用数据库配置选项加快连接操作的选项之后,我现在尝试使用数据库触发器来维护与其聚合连接的假期的物化视图。
SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_name = 'vacation_materialized';
column_name
--------------
id
location_id
location$data
travel_agency_id
travel_agency$data
airline_id
airline$data
现在我正在权衡如何从这个视图重建假期,travel_agency和航空公司对象的选项。一种选择是使用sqlalchemy核心查询vacation_materialized表,然后解析行并“手动”构造对象。是否有任何我应该研究的ORM功能可能会产生更“优雅”的解决方案?
答案 0 :(得分:2)
您应该能够针对物化视图映射类,然后提供只读关系属性:
materialized_vacations = Table('materialized_vacations', metadata, autoload=True)
locations = Table('locations', metadata, autoload=True)
mvac_2_location = materialized_vacations.c.location_id==locations.c.location_id
class Location(Base):
__table__ = locations
class MaterializedVacation(Base):
__table__ = materialized_vacations
location = relationship("Location", primaryjoin=mvac_2_location, viewonly=True)
...
我假设您不想要将任何外键放入物化视图中。相反,我使用primaryjoin
的{{1}}关键字参数明确指定了连接条件。
此处relationship()
创建mvac_2_location
;我喜欢在使用之前单独声明它们,因为它们倾向于自己占用大部分行,并且如果声明它们被使用的地方,则使参数序列不可读。它还使它们可以重复使用并可导入子模块,这可以很方便。
要构造sqlalchemy.sql.expression.BinaryExpression
,我需要实际的表对象,在完成类mvac_2_location
的声明之前我需要它们,所以我将它们声明为老式的预声明方式然后绑定使用声明性参数MaterializedVacation
代替更常见的__table__
的表的类。有可能有更好的方法来做到这一点,但我不确定。