2016-10-14 64 views
1

我有以下代表时间线的Table模型。SQLAlchemy:如何查询自引用邻接列表表上的可选列?

class TimeRange(Base): 


    __tablename__ = "time_line" 


    record_id = Column(Integer, primary_key=True) 
    level = Column(String, nullable=False) # e.g. "Point", "Range" 
    content = Column(String, nullable=False) 
    language_marker = Column(String) # this one column is optional and needs to be queried 
    immediate_parent_id = Column(Integer, ForeignKey('time_line.record_id')) 
    child_timelines = relationship('TimeRange', backref=backref('parent_timeline', remote_side=[record_id])) 

language_marker列是需要以递归方式要查询的一个。并非所有记录都具有这样的属性,并且业务逻辑是:沿着从根到子时间轴的层次结构沿袭至少一个级别的实例携带这样的属性,并且应该返回最低级别的属性。这有点像级联样式表,如果TimeRange对象本身没有这样的属性,只需再往上看一级,util找到一个,并且最新定义的样式获胜。

我应该考虑实施这些查询的技术方向是什么?我使用的是SQLAlchemy,而后端是SQLite。谢谢。

+0

当'language_marker'是'None'时,为父'TimeRange'选择查询性能好吗? – xli

+0

@xli,谢谢你的回复。这绝对没问题。现在我对这里的技术方向毫无头绪。你能提供更多细节吗? –

回答

1

,直到它找到一个language_marker不是None并返回我想补充一点,与当前对象开始直到父的层次TimeRange个属性derived_language_marker

@property 
def derived_language_marker(self): 
    time_range = self 
    while not time_range.language_marker and time_range.parent_timeline: 
     time_range = time_range.parent_timeline 
    return time_range.language_marker 

可以只访问作为time_range.derived_language_marker,但缺点是它可能会导致一个新的SELECT查询每个级别它检查父对象是否尚未加载。

(如果你这样做了很多TimeRange s并且性能成为问题,只要最大可能的深度不太过分,就可以使用here中描述的连接将祖先热切加载到特定深度。优化,也有this approach为SQLite)

+0

再加上简洁和实用性。我希望我能再添加一个优雅。 –

+0

可以给你多一点解释为什么使用property而不是hybrid_property,或者直接在TimeRange上直接使用纯属性?谢谢。 –

+1

'hybrid_property'可以让你在'derived_language_marker'上查询(比如'filter(derived_language_marker == some_value)'),但是它需要将逻辑转换成一个SQL表达式,这是不可能的它现在是。如果您需要这样的功能,您可以尝试查看第二个链接。使用普通属性时,您需要在表中创建列,但是您需要不断更新该列。 – xli