如何在SQLAlchemy中实现一个追加模式的版本化模型

13
我想重新实现一些已有的SQLAlchemy模型,使用仅追加的数据存储方式;即只使用INSERT语句更新对象,而不使用UPDATE或DELETE语句。
UPDATE和DELETE语句将被替换为另一个插入语句,该语句将增加版本号。将有一个“is_deleted”标志,而不是DELETE,将创建一个带有“is_deleted=True”的新版本:
id  | version | is_deleted | name      | description ...
---- --------- ------------ ----------- ---------------
  1 |       1 |          F | Fo        | Text text text.
  1 |       2 |          F | Foo       | Text text text.
  2 |       1 |          F | Bar       | null 
  1 |       3 |          T | Foo       | Text text text.         

此外,需要将所有SELECT语句重写为每个id的最大版本号,具体方法请参考这个问题:PostgreSQL-获取列中最大值的行。还需要将所有(唯一的)索引重写为以" id "主键为唯一标识,因为每个id可能会出现多次。
我知道如何解决大部分的问题,但我在SQLAlchemy中的事件钩子方面遇到了困难,这些事件钩子需要处理某些需要在更新和删除时完成的操作。
SQLAlchemy文档已经提供了一些基本的版本控制示例。 versioned rows 示例接近我想要的内容,但它们不处理 (1) 删除和 (2) 外键关系。

(1) 删除。我知道有一个session.deleted字段,我会以类似于在versioned_rows.py示例中迭代session.dirty的方式迭代它——但是如何取消标记要删除的项目并创建一个新项目呢?

(2) 上述示例仅处理父子关系,而且它所做的(过期关系)似乎需要为每个模型编写自定义代码。(2.1) 有没有办法使这更加灵活?(2.2) 是否可以配置SQLAlchemy的relationship()返回给定外键的最大版本对象?


1
你要找的术语是“软删除”。我不太了解SQLAlchemy,但也许这会对你有所帮助。个人而言,我可能会在数据库端使用触发器来完成这个操作。 - Craig Ringer
谢谢 - 我在软删除中找到了这个,它有助于我问题的第一部分 http://stackoverflow.com/questions/23198801/sqlalchemy-using-aliased-in-query-with-custom-primaryjoin-relationship 对我来说,使用数据库触发器不是一个选项,因为我的模型经常更改,并且迁移工具(如alembic)无法很好地处理触发器。 - lyschoening
1
好奇的问题,我也很想看看如何处理这个问题的例子。关于链接到max(version)更好的方法可能是不要在Head版本中使用版本号,这样您就可以直接加入最新记录(version == None)。数据需要在同一张表中吗?只是想知道版本对象系统(它创建第二个表,blah_history)是否可以简化事情http://docs.sqlalchemy.org/en/latest/orm/examples.html#versioning-objects。它还处理删除操作,因为整个版本历史记录都可在辅助表中获得。 - Aidan Kane
你能为追踪记录新增一张表吗?我想这类似于历史/版本模型,其中一张表是活动状态,而另一张表只是历史状态。 - Aidan Kane
看一下连续体 - 它以类似的方式保留相关表的副本。 - Aidan Kane
显示剩余6条评论
2个回答

2
一种对ORM工具无关的有用方法可能是“替代”触发器。例如,您可以捕获更新前事件,并使用新更新的数据打开一个递增版本号。
对于postgresql,它们在这里中有详细说明。
当然,您必须进行模型更改(在PK等方面)。
此外,值得研究性能影响,因为您可能需要递归查询才能获取“最新版本”(通过视图层或在SQLAlchemy中的where子句等)。

0

虽然这可能听起来有些疯狂,但实际上使用不同类型的数据库可能会更好。您是否了解Datomic?传统关系型数据库管理系统(RDBMS)和这种类型的系统之间的一个基本区别是,没有原地更新,这是RDBMS在磁盘上更新文件的方式。相反,一切都是版本化的,您可以回到每个单独资源的每个更改的所有先前版本的数据库。此外,您可以通过将感兴趣的时间作为参数来轻松查看特定时刻整个数据库的状态。还有很多其他有趣的优点,我强烈建议您查看一下Rich Hickey的一些演讲,例如this one。这绝对是一种根本不同的方法,与您当前尝试的方法有所不同,但必须考虑是否要在每一步中与工具进行斗争,以一种它们真正没有设计的方式使用它们(如RDBMS、ORM、迁移管理器等)。相反,您可以将该复杂性下推一层,并让不同类型的数据库为您处理。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接