表继承映射与对象关系数据库中的组合
我最近开始使用SQLAlchemy,但之前对SQL没有任何了解。我遇到的一个问题是如何引入多态行为。举个例子,想象一个类似Reddit的网站应用;我们有一个Article
(文章)模型和一个Comment
(评论)模型,它们都可以被投票:
class Article(Base):
id = Column(Integer, primary_key = True)
data = Column(Text)
comments = relationship('Comment')
#... more article-related attributes
votes = relationship('Vote')
vote_ups = Column(Integer, default = 0)
vote_downs = Column(Integer, default = 0)
class Comment(Base):
id = Column(Integer, primary_key = True)
data = Column(Text)
#... more comment-related attributes
votes = relationship('Vote')
vote_ups = Column(Integer, default = 0)
vote_downs = Column(Integer, default = 0)
我想把投票的属性分离出来,因为这两个模型都有这些属性,这样我就不需要为每个可以投票的模型重复代码。
我最初的想法是创建一个新的VotesComponent
(投票组件)模型,把这些属性放进去,如下所示:
class VotesComponent(Base):
votes = relationship('Vote')
vote_ups = Column(Integer)
vote_downs = Column(Integer)
然后和Comment
(评论)和Article
(文章)模型建立多对一的关系。
在查阅SQLAlchemy的文档时,我发现可以通过使用连接表继承来实现类似的功能。一开始这看起来很方便,因为避免了额外的间接引用(也就是说,可以直接用comment.votes而不是comment.votes_component.votes),但我有限的理解中看到的一个大缺点是,不支持多重继承,而用之前的方法,可以自由地为模型添加多个“组件”。
所以,我的问题是,使用继承映射相比于组合有什么好处,什么时候更适合使用其中一种,为什么?在这种情况下,你会推荐哪种方法(或者可能是其他不同的方法)?
编辑:我应该提到,我希望能够单独查询模型的“投票”部分,这样我就可以以多态的方式处理投票。
1 个回答
这个问题很好,但在这里有点偏题,因为在StackOverflow上,大家不太喜欢那些需要主观意见的问题。不过,我还是想分享一下我的个人看法(我真的不想引发争论)。
我的问题是,使用继承映射有什么好处,相比之下,组合又是什么时候更合适,为什么?
在大多数面向对象的编程语言中,继承通常与“是一个”的关系有关,而组合则与“有一个”的关系有关。在Python中,组合通常通过多重继承来实现,所以“组合和继承”的讨论有点奇怪。Python提倡一种叫做鸭子类型的风格,因此“有一个”的问题被认为更符合语言的习惯。
当我们谈论对象关系映射(ORM)时,还有其他的考虑:继承是如何在底层实现的?有些实现会把对象数据分散到多个表中,并进行SQL连接(JOIN),而其他的则会使用单个表并进行SQL并集(UNION)。在我看来,这些细节不值得你花太多精力去思考。第一个原因是,这些对你来说是透明的,这就是使用ORM的目的。第二,你可能缺乏判断哪种方式更适合你特定情况的知识(你需要深入了解SQL和各种关系数据库管理系统的具体实现细节,才能理解其中的性能影响)。
我的建议是,按照你喜欢的编程风格来实现,信任ORM的选择,把性能问题留给数据库管理员(DBA)去处理。