数据库结构
我有两个类,A 和 B,它们有两种不同的关系:
1) 使用关联表 (associations) 存储仅与该特定关联 (association_property_1) 相关的信息并通过 A 和 B 中的反向引用实例化的多对多关系。
2) A 和 B 之间使用 table_b 中的外键建立一对一关系,这样只有 B“知道”这种关系。我不在乎 A 是否知道它,但这样看起来更简单。
我的课程如下所示:
class A(Base):
__tablename__ = 'table_a'
id = Column(Integer, primary_key=True)
a_property_1 = Column(Float)
a_property_2 = Column(Float)
a_property_special = Column(Float)
# Many-to-many relationship with B through an Association
associated_bs = relationship('Association', backref='a')
class B(Base):
__tablename__ = 'table_b'
id = Column(Integer, primary_key=True)
b_property_1 = Column(Float)
b_property_2 = Column(Float)
# One-to-one relationship with A
a_id = Column(Integer, ForeignKey('table_a.id'))
a = relationship('A', uselist=False, backref='b')
# Many-to-many relationship with A through an Association
associated_as = relationship('Association', backref='b')
class Association(Base):
__tablename__ = 'associations'
a_id = Column(Integer, ForeignKey('table_a.id'), primary_key=True)
b_id = Column(Integer, ForeignKey('table_b.id'), primary_key=True)
association_property_1 = Column(Float)
程序
我想对所有关联运行查询,我可以通过与 B 的一对一关系访问 A 的特殊属性。所以基本上我希望能够访问该属性
B.a.a_property_special
在查询中。
特定查询的示例如下:
session.query(Association.association_property_1,
func.abs(A.a_property_special - B.a.a_property_special).\
filter(B.a.a_property_special > 3.0)
其中 A 和 B 使用多对多关系连接,Ba 通过一对一连接。显然这个查询不会工作,因为 B 没有实例化,所以我无法访问 Baa_property_special。
如果我没有多对多关系,我可以在 B 上加入 A 并完成它。我的问题是我想使用关联查询 A 和 B,但我仍然需要通过一对一关系的标量 Baa_property_special。
可能的解决方案
我尝试了几种不同的解决方案,但由于各种原因都证明不令人满意。
- 将列“a_property_special”复制到表 B。我不喜欢这样,因为如果 A 和 B 之间的一对一关系发生变化(它可能在运行时发生变化),它会复制信息并且不会呈现良好的逻辑数据结构。
- 使用 column_property 或 association_proxy。看起来很干净,但我只能让它在实例对象上正常工作。在查询中使用它们时,我在构建二进制表达式等时遇到问题。
- 使用子查询。我已经摆弄了一点,但一直无法生产出任何运作良好的东西。也许我只是做得不对,但它似乎总是最终变得非常混乱和缓慢。
- 只需查询所有关联并在 python 中进行数学、逻辑表达式和过滤。我的感觉是这会比在 SQL 中效率低,但我可能是错的..
要求
- 它需要很快(呃)。我的表有几次,每个表都有 100,000 条记录。
- 查询必须尽可能简单,以便易于调试和修改,同时仍能反映数据库的逻辑结构。我更愿意将尽可能多的代码隐藏在类定义中。
- 我对关系的结构没有任何特别的偏好,我只需要一对一和多对多(包括它自己的关联属性)。
我有一种感觉,这真的很简单,但我似乎无法找到一个好的解决方案。欢迎任何帮助或评论。